diff options
35 files changed, 773 insertions, 223 deletions
diff --git a/Android.bp b/Android.bp index 2c2114b2..5d6f0433 100644 --- a/Android.bp +++ b/Android.bp @@ -1,7 +1,16 @@ cc_defaults { name: "afl-defaults", + sanitize: { + never: true, + }, + + local_include_dirs: [ + "include", + "instrumentation", + ], cflags: [ + "-flto=full", "-funroll-loops", "-Wno-pointer-sign", "-Wno-pointer-arith", @@ -10,16 +19,22 @@ cc_defaults { "-Wno-unused-function", "-Wno-format", "-Wno-user-defined-warnings", - "-DUSE_TRACE_PC=1", + "-DAFL_LLVM_USE_TRACE_PC=1", "-DBIN_PATH=\"out/host/linux-x86/bin\"", "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"", "-D__USE_GNU", + "-D__aarch64__", + "-DDEBUG_BUILD", + "-U_FORTIFY_SOURCE", + "-ggdb3", + "-g", + "-O0", + "-fno-omit-frame-pointer", ], } cc_binary { name: "afl-fuzz", - static_executable: true, host_supported: true, defaults: [ @@ -27,7 +42,11 @@ cc_binary { ], srcs: [ - "afl-fuzz.c", + "src/afl-fuzz*.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", ], } @@ -41,7 +60,10 @@ cc_binary { ], srcs: [ - "afl-showmap.c", + "src/afl-showmap.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", ], } @@ -55,7 +77,11 @@ cc_binary { ], srcs: [ - "afl-tmin.c", + "src/afl-tmin.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", ], } @@ -69,7 +95,10 @@ cc_binary { ], srcs: [ - "afl-analyze.c", + "src/afl-analyze.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-performance.c", ], } @@ -83,12 +112,13 @@ cc_binary { ], srcs: [ - "afl-gotcpu.c", + "src/afl-gotcpu.c", + "src/afl-common.c", ], } cc_binary_host { - name: "afl-clang-fast", + name: "afl-cc", static_executable: true, defaults: [ @@ -98,44 +128,144 @@ cc_binary_host { cflags: [ "-D__ANDROID__", "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + "-DAFL_CLANG_FLTO=\"-flto=full\"", + "-DUSE_BINDIR=1", + "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"", + "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"", + "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"", + "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"", + "-DLLVM_LTO=1", + "-DLLVM_MAJOR=11", + "-DLLVM_MINOR=2", ], srcs: [ "src/afl-cc.c", + "src/afl-common.c", + ], + + symlinks: [ + "afl-clang-fast", + "afl-clang-fast++", ], } -cc_binary_host { - name: "afl-clang-fast++", - static_executable: true, +cc_library_static { + name: "afl-llvm-rt", + compile_multilib: "both", + vendor_available: true, + host_supported: true, + recovery_available: true, + sdk_version: "9", - defaults: [ - "afl-defaults", + apex_available: [ + "com.android.adbd", + "com.android.appsearch", + "com.android.art", + "com.android.bluetooth.updatable", + "com.android.cellbroadcast", + "com.android.conscrypt", + "com.android.extservices", + "com.android.cronet", + "com.android.neuralnetworks", + "com.android.media", + "com.android.media.swcodec", + "com.android.mediaprovider", + "com.android.permission", + "com.android.runtime", + "com.android.resolv", + "com.android.tethering", + "com.android.wifi", + "com.android.sdkext", + "com.android.os.statsd", + "//any", ], - cflags: [ - "-D__ANDROID__", - "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + defaults: [ + "afl-defaults", ], srcs: [ - "src/afl-cc.c", + "instrumentation/afl-compiler-rt.o.c", ], } -cc_library_static { - name: "afl-llvm-rt", - compile_multilib: "both", +cc_library_headers { + name: "libafl_headers", vendor_available: true, host_supported: true, - recovery_available: true, - sdk_version: "9", + + export_include_dirs: [ + "include", + ], +} + +cc_prebuilt_library_static { + name: "libfrida-gum", + compile_multilib: "64", + strip: { + none: true, + }, + + srcs: [ + "utils/afl_frida/android/libfrida-gum.a", + ], + + export_include_dirs: [ + "utils/afl_frida/android", + ], +} + +cc_library_shared { + name: "libtestinstr", + + srcs: [ + "utils/afl_frida/libtestinstr.c", + ], + + cflags: [ + "-O0", + "-fPIC", + ], +} + +cc_binary { + name: "afl-frida", + compile_multilib: "64", defaults: [ "afl-defaults", ], + cflags: [ + "-g", + "-O0", + "-Wno-format", + "-Wno-pointer-sign", + "-fpermissive", + "-fPIC", + ], + + static_libs: [ + "afl-llvm-rt", + "libfrida-gum", + ], + + shared_libs: [ + "libdl", + "liblog", + ], + srcs: [ - "instrumentation/afl-llvm-rt.o.c", + "utils/afl_frida/afl-frida.c", + ], + + local_include_dirs: [ + "utils/afl_frida", + "utils/afl_frida/android", ], } + +subdirs = [ + "custom_mutators", +] diff --git a/Android.mk b/Android.mk deleted file mode 120000 index 33ceb8f0..00000000 --- a/Android.mk +++ /dev/null @@ -1 +0,0 @@ -Makefile \ No newline at end of file diff --git a/README.md b/README.md index 9c0e3339..ce48f336 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ ## Major changes in afl++ 3.0 -With afl++ 3.0 we introduced changes that break some previous afl and afl++ +With afl++ 3.0 we introduced changes that breaks some previous afl and afl++ behaviours and defaults: * There are no llvm_mode and gcc_plugin subdirectories anymore and there is only one compiler: afl-cc. All previous compilers now symlink to this. All instrumentation source code is now in the `instrumentation/` folder. * The gcc_plugin was replaced with a new version submitted by AdaCore that - supports more features. thank you! + supports more features. Thank you! * qemu_mode got upgraded to QEMU 5.1, but to be able to build this a current ninja build tool version and python3 setuptools are required. qemu_mode also got new options like snapshotting, instrumenting specific @@ -1107,7 +1107,7 @@ without feedback, bug reports, or patches from: Khaled Yakdan Kuang-che Wu Josephine Calliotte Konrad Welc Thomas Rooijakkers David Carlier - Ruben ten Hove + Ruben ten Hove Joey Jiao ``` Thank you! diff --git a/afl-wine-trace b/afl-wine-trace index 8853a757..63ff896b 100755 --- a/afl-wine-trace +++ b/afl-wine-trace @@ -28,9 +28,9 @@ if not os.getenv("AFL_INST_LIBS"): os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode) if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]: - os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64" else: - os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32" if os.getenv("WINECOV_QEMU_PATH"): qemu_path = os.getenv("WINECOV_QEMU_PATH") diff --git a/custom_mutators/Android.bp b/custom_mutators/Android.bp new file mode 100644 index 00000000..89abc3e9 --- /dev/null +++ b/custom_mutators/Android.bp @@ -0,0 +1,115 @@ +cc_library_shared { + name: "libfuzzer-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + "-fpermissive", + "-std=c++11", + ], + + srcs: [ + "libfuzzer/FuzzerCrossOver.cpp", + "libfuzzer/FuzzerDataFlowTrace.cpp", + "libfuzzer/FuzzerDriver.cpp", + "libfuzzer/FuzzerExtFunctionsDlsym.cpp", + "libfuzzer/FuzzerExtFunctionsWeak.cpp", + "libfuzzer/FuzzerExtFunctionsWindows.cpp", + "libfuzzer/FuzzerExtraCounters.cpp", + "libfuzzer/FuzzerFork.cpp", + "libfuzzer/FuzzerIO.cpp", + "libfuzzer/FuzzerIOPosix.cpp", + "libfuzzer/FuzzerIOWindows.cpp", + "libfuzzer/FuzzerLoop.cpp", + "libfuzzer/FuzzerMerge.cpp", + "libfuzzer/FuzzerMutate.cpp", + "libfuzzer/FuzzerSHA1.cpp", + "libfuzzer/FuzzerTracePC.cpp", + "libfuzzer/FuzzerUtil.cpp", + "libfuzzer/FuzzerUtilDarwin.cpp", + "libfuzzer/FuzzerUtilFuchsia.cpp", + "libfuzzer/FuzzerUtilLinux.cpp", + "libfuzzer/FuzzerUtilPosix.cpp", + "libfuzzer/FuzzerUtilWindows.cpp", + "libfuzzer/libfuzzer.cpp", + ], + + header_libs: [ + "libafl_headers", + ], +} + +/*cc_library_shared { + name: "honggfuzz-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + "-Wl,-Bsymbolic", + ], + + srcs: [ + "honggfuzz/honggfuzz.c", + "honggfuzz/mangle.c", +// "../src/afl-perfomance.c", + ], + + header_libs: [ + "libafl_headers", + ], +}*/ + +cc_library_shared { + name: "radamsa-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + ], + + srcs: [ + "radamsa/libradamsa.c", + "radamsa/radamsa-mutator.c", + ], + + header_libs: [ + "libafl_headers", + ], +} + +cc_library_shared { + name: "symcc-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + ], + + srcs: [ + "symcc/symcc.c", + ], + + header_libs: [ + "libafl_headers", + ], +} + +subdirs = [ + "libprotobuf-mutator-example", +] diff --git a/custom_mutators/libprotobuf-mutator-example/Android.bp b/custom_mutators/libprotobuf-mutator-example/Android.bp new file mode 100644 index 00000000..01f1c23e --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/Android.bp @@ -0,0 +1,32 @@ +cc_library_shared { + name: "libprotobuf-mutator-example-afl", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-fPIC", + "-Wall", + ], + + srcs: [ + "lpm_aflpp_custom_mutator_input.cc", + "test.proto", + ], + + shared_libs: [ + "libprotobuf-cpp-full", + "libprotobuf-mutator", + ], +} + +cc_binary { + name: "libprotobuf-mutator-vuln", + vendor_available: true, + host_supported: true, + + srcs: [ + "vuln.c", + ], +} diff --git a/custom_mutators/libprotobuf-mutator-example/README.md b/custom_mutators/libprotobuf-mutator-example/README.md new file mode 100644 index 00000000..5a844c00 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/README.md @@ -0,0 +1 @@ +Ported from [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input) diff --git a/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc new file mode 100644 index 00000000..e0273849 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc @@ -0,0 +1,118 @@ +#include "lpm_aflpp_custom_mutator_input.h" +#include <iostream> +#include <sstream> +#include <fstream> + +using std::cin; +using std::cout; +using std::endl; + +std::string ProtoToData(const TEST &test_proto) { + std::stringstream all; + const auto &aa = test_proto.a(); + const auto &bb = test_proto.b(); + all.write((const char*)&aa, sizeof(aa)); + if(bb.size() != 0) { + all.write(bb.c_str(), bb.size()); + } + + std::string res = all.str(); + if (bb.size() != 0 && res.size() != 0) { + // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf + if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { + std::ofstream of(dump_path); + of.write(res.data(), res.size()); + } + } + return res; +} + +/** + * Initialize this custom mutator + * + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * in the same way. + * @return Pointer to the data object this custom mutator instance should use. + * There may be multiple instances of this mutator in one afl-fuzz run! + * Return NULL on error. + */ +extern "C" MyMutator *afl_custom_init(void *afl, unsigned int seed) { + MyMutator *mutator = new MyMutator(); + + mutator->RegisterPostProcessor( + TEST::descriptor(), + [](google::protobuf::Message* message, unsigned int seed) { + // libprotobuf-mutator's built-in mutator is kind of....crappy :P + // Even a dumb fuzz like `TEST.a = rand();` is better in this case... Q_Q + // We register a post processor to apply our dumb fuzz + + TEST *t = static_cast<TEST *>(message); + t->set_a(rand()); + }); + + srand(seed); + return mutator; +} + +/** + * Perform custom mutations on a given input + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to input data to be mutated + * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. + * @param[in] add_buf Buffer containing the additional test case + * @param[in] add_buf_size Size of the additional test case + * @param[in] max_size Maximum size of the mutated output. The mutation must not + * produce data larger than max_size. + * @return Size of the mutated output. + */ +extern "C" size_t afl_custom_fuzz(MyMutator *mutator, // return value from afl_custom_init + uint8_t *buf, size_t buf_size, // input data to be mutated + uint8_t **out_buf, // output buffer + uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + // This function can be named either "afl_custom_fuzz" or "afl_custom_mutator" + // A simple test shows that "buf" will be the content of the current test case + // "add_buf" will be the next test case ( from AFL++'s input queue ) + + TEST input; + // parse input data to TEST + // Notice that input data should be a serialized protobuf data + // Check ./in/ii and test_protobuf_serializer for more detail + bool parse_ok = input.ParseFromArray(buf, buf_size); + if(!parse_ok) { + // Invalid serialize protobuf data. Don't mutate. + // Return a dummy buffer. Also mutated_size = 0 + static uint8_t *dummy = new uint8_t[10]; // dummy buffer with no data + *out_buf = dummy; + return 0; + } + // mutate the protobuf + mutator->Mutate(&input, max_size); + + // Convert protobuf to raw data + const TEST *p = &input; + std::string s = ProtoToData(*p); + // Copy to a new buffer ( mutated_out ) + size_t mutated_size = s.size() <= max_size ? s.size() : max_size; // check if raw data's size is larger than max_size + uint8_t *mutated_out = new uint8_t[mutated_size+1]; + memcpy(mutated_out, s.c_str(), mutated_size); // copy the mutated data + // Assign the mutated data and return mutated_size + *out_buf = mutated_out; + return mutated_size; +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +extern "C" void afl_custom_deinit(void *data) { + // Honestly I don't know what to do with this... + return; +} + diff --git a/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h new file mode 100644 index 00000000..ebd3ca65 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h @@ -0,0 +1,5 @@ +#include <src/mutator.h> +#include "test.pb.h" + +class MyMutator : public protobuf_mutator::Mutator { +}; diff --git a/custom_mutators/libprotobuf-mutator-example/test.proto b/custom_mutators/libprotobuf-mutator-example/test.proto new file mode 100644 index 00000000..e2256c6e --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/test.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +message TEST { + required uint32 a = 1; + required string b = 2; +} + diff --git a/custom_mutators/libprotobuf-mutator-example/vuln.c b/custom_mutators/libprotobuf-mutator-example/vuln.c new file mode 100644 index 00000000..8ffb7080 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/vuln.c @@ -0,0 +1,17 @@ +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + char str[100]={}; + read(0, str, 100); + int *ptr = NULL; + if( str[0] == '\x02' || str[0] == '\xe8') { + *ptr = 123; + } + return 0; +} + diff --git a/docs/Changelog.md b/docs/Changelog.md index e0f8e9bf..60f09ca5 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,6 +19,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. for reporting) - if determinstic mode is active (-D, or -M without -d) then we sync after every queue entry as this can take very long time otherwise + - better detection if a target needs a large shared map - switched to a faster RNG - added hghwng's patch for faster trace map analysis - afl-cc diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 621e8745..f46d7707 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -37,10 +37,6 @@ #define _FILE_OFFSET_BITS 64 #endif -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 41d4d2da..6939e06d 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -1,112 +1,81 @@ -/* - american fuzzy lop++ - android shared memory compatibility layer - ---------------------------------------------------------------- - - Originally written by Michal Zalewski - - Now maintained by Marc Heuse <mh@mh-sec.de>, - Heiko Eißfeldt <heiko.eissfeldt@hexco.de>, - Andrea Fioraldi <andreafioraldi@gmail.com>, - Dominik Maier <mail@dmnk.co> - - Copyright 2016, 2017 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 - - This header re-defines the shared memory routines used by AFL++ - using the Andoid API. - - */ - +#ifdef __ANDROID__ #ifndef _ANDROID_ASHMEM_H #define _ANDROID_ASHMEM_H -#ifdef __ANDROID__ - - #include <fcntl.h> - #include <linux/shm.h> - #include <linux/ashmem.h> - #include <sys/ioctl.h> - #include <sys/mman.h> - - #if __ANDROID_API__ >= 26 - #define shmat bionic_shmat - #define shmctl bionic_shmctl - #define shmdt bionic_shmdt - #define shmget bionic_shmget - #endif - - #include <sys/shm.h> - #undef shmat - #undef shmctl - #undef shmdt - #undef shmget - #include <stdio.h> +#include <fcntl.h> +#include <linux/ashmem.h> +#include <sys/ioctl.h> +#include <sys/mman.h> - #define ASHMEM_DEVICE "/dev/ashmem" +#if __ANDROID_API__ >= 26 +#define shmat bionic_shmat +#define shmctl bionic_shmctl +#define shmdt bionic_shmdt +#define shmget bionic_shmget +#endif +#include <sys/shm.h> +#undef shmat +#undef shmctl +#undef shmdt +#undef shmget +#include <stdio.h> -static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { +#define ASHMEM_DEVICE "/dev/ashmem" +int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - struct ashmem_pin pin = {0, (unsigned int)length}; + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); - } return ret; - } -static inline int shmget(key_t __key, size_t __size, int __shmflg) { - - (void)__shmflg; - int fd, ret; +int shmget(key_t __key, size_t __size, int __shmflg) { + (void) __shmflg; + int fd, ret; char ourkey[11]; fd = open(ASHMEM_DEVICE, O_RDWR); - if (fd < 0) return fd; + if (fd < 0) + return fd; sprintf(ourkey, "%d", __key); ret = ioctl(fd, ASHMEM_SET_NAME, ourkey); - if (ret < 0) goto error; + if (ret < 0) + goto error; ret = ioctl(fd, ASHMEM_SET_SIZE, __size); - if (ret < 0) goto error; + if (ret < 0) + goto error; return fd; error: close(fd); return ret; - } -static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { - - (void)__shmflg; - int size; +void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { + (void) __shmflg; + int size; void *ptr; size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - if (size < 0) { return NULL; } + if (size < 0) { + return NULL; + } ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0); - if (ptr == MAP_FAILED) { return NULL; } + if (ptr == MAP_FAILED) { + return NULL; + } return ptr; - } -#endif /* __ANDROID__ */ - -#endif - +#endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/include/config.h b/include/config.h index c9c4a677..b5137553 100644 --- a/include/config.h +++ b/include/config.h @@ -192,7 +192,7 @@ /* The same, for the test case minimizer: */ -#define TMIN_MAX_FILE (10 * 1024 * 1024U) +#define TMIN_MAX_FILE (10 * 1024 * 1024) /* Block normalization steps for afl-tmin: */ diff --git a/instrumentation/README.instrument_list.md b/instrumentation/README.instrument_list.md index 83197954..b47b50f6 100644 --- a/instrumentation/README.instrument_list.md +++ b/instrumentation/README.instrument_list.md @@ -41,7 +41,7 @@ in any function where you want: * `__AFL_COVERAGE_ON();` - enable coverage from this point onwards * `__AFL_COVERAGE_OFF();` - disable coverage from this point onwards * `__AFL_COVERAGE_DISCARD();` - reset all coverage gathered until this point - * `__AFL_COVERAGE_ABORT();` - mark this test case as unimportant. Whatever happens, afl-fuzz will ignore it. + * `__AFL_COVERAGE_SKIP();` - mark this test case as unimportant. Whatever happens, afl-fuzz will ignore it. ## 3) Selective instrumenation with AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 1d7ac934..016ac71f 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1111,7 +1111,7 @@ bool ModuleSanitizerCoverage::instrumentModule( getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); OKF("Instrumented %u locations with no collisions (on average %llu " - "collisions would be in afl-gcc/afl-clang-fast) (%s mode).", + "collisions would be in afl-gcc/vanilla AFL) (%s mode).", inst, calculateCollisions(inst), modeline); } diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index de01cb69..14da4caa 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1636,7 +1636,7 @@ void __afl_coverage_discard() { } // discard the testcase -void __afl_coverage_abort() { +void __afl_coverage_skip() { __afl_coverage_discard(); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 9cacacf9..13dca8c4 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -1033,7 +1033,7 @@ bool AFLLTOPass::runOnModule(Module &M) { getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); OKF("Instrumented %d locations with no collisions (on average %llu " - "collisions would be in afl-gcc/afl-clang-fast) (%s mode).", + "collisions would be in afl-gcc/vanilla AFL) (%s mode).", inst_blocks, calculateCollisions(inst_blocks), modeline); } diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl -Subproject 5400ce883a751582473665d8fd18f8e8f9d14cd +Subproject 21ff34383764a8c6f66509b3b8d5282468c721e diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 8fc4434a..0af489fe 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -26,9 +26,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/src/afl-cc.c b/src/afl-cc.c index 2ce986c7..b0b11f48 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -586,6 +586,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_PCGUARD) { #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) +#ifdef __ANDROID__ + cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; +#else if (have_instr_list) { if (!be_quiet) @@ -605,6 +608,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } +#endif #else #if LLVM_MAJOR >= 4 if (!be_quiet) @@ -834,7 +838,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;" "extern \"C\" void __afl_coverage_discard();" - "extern \"C\" void __afl_coverage_abort();" + "extern \"C\" void __afl_coverage_skip();" "extern \"C\" void __afl_coverage_on();" "extern \"C\" void __afl_coverage_off();"; @@ -843,7 +847,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;" "void __afl_coverage_discard();" - "void __afl_coverage_abort();" + "void __afl_coverage_skip();" "void __afl_coverage_on();" "void __afl_coverage_off();"; @@ -1031,6 +1035,10 @@ int main(int argc, char **argv, char **envp) { #endif +#ifdef __ANDROID__ + have_llvm = 1; +#endif + if ((ptr = find_object("afl-gcc-pass.so", argv[0])) != NULL) { have_gcc_plugin = 1; @@ -1802,11 +1810,8 @@ int main(int argc, char **argv, char **envp) { if (!be_quiet && cmplog_mode) printf("CmpLog mode by <andreafioraldi@gmail.com>\n"); -#ifdef __ANDROID__ - ptr = find_object("afl-compiler-rt.so", argv[0]); -#else +#ifndef __ANDROID__ ptr = find_object("afl-compiler-rt.o", argv[0]); -#endif if (!ptr) { @@ -1819,6 +1824,7 @@ int main(int argc, char **argv, char **envp) { if (debug) { DEBUGF("rt=%s obj_path=%s\n", ptr, obj_path); } ck_free(ptr); +#endif edit_params(argc, argv, envp); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index ed8c2510..586f3990 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -703,7 +703,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (!classified) { classify_counts(&afl->fsrv); - // classified = 1; } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 089707b9..80df6d08 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -141,7 +141,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); mutator->name = fn; - mutator->name_short = strrchr(fn, '/') + 1; + if (memchr(fn, '/', strlen(fn))) + mutator->name_short = strrchr(fn, '/') + 1; + else + mutator->name_short = strdup(fn); ACTF("Loading custom mutator library from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index b597488b..17c305ed 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -424,7 +424,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (unlikely(afl->fixed_seed)) { - diff_us = (afl->fsrv.exec_tmout - 1) * afl->stage_max; + diff_us = (u64)(afl->fsrv.exec_tmout - 1) * (u64)afl->stage_max; } else { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index e86f2aeb..e67bace9 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -58,7 +58,11 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { for (i = 0; i < argc; ++i) { if (i) fprintf(f, " "); +#ifdef __ANDROID__ + if (memchr(argv[i], '\'', sizeof(argv[i]))) { +#else if (index(argv[i], '\'')) { +#endif fprintf(f, "'"); for (j = 0; j < strlen(argv[i]); j++) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 88c40ee8..95bc0694 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -584,7 +584,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->timeout_given) { FATAL("Multiple -t options not supported"); } - if (sscanf(optarg, "%u%c", &afl->fsrv.exec_tmout, &suffix) < 1 || + if (!optarg || sscanf(optarg, "%u%c", &afl->fsrv.exec_tmout, &suffix) < 1 || optarg[0] == '-') { FATAL("Bad syntax used for -t"); @@ -766,7 +766,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'V': { afl->most_time_key = 1; - if (sscanf(optarg, "%llu", &afl->most_time) < 1 || optarg[0] == '-') { + if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 || optarg[0] == '-') { FATAL("Bad syntax used for -V"); @@ -777,7 +777,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'E': { afl->most_execs_key = 1; - if (sscanf(optarg, "%llu", &afl->most_execs) < 1 || optarg[0] == '-') { + if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 || optarg[0] == '-') { FATAL("Bad syntax used for -E"); diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c index 1aea3e40..ac002a93 100644 --- a/src/afl-gotcpu.c +++ b/src/afl-gotcpu.c @@ -35,9 +35,6 @@ #define _GNU_SOURCE #endif -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include <stdio.h> #include <stdlib.h> #include <unistd.h> diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 7a4d9132..0671d1c4 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -253,7 +253,6 @@ static void edit_params(int argc, char **argv) { int main(int argc, char **argv) { s32 pid, i, status; - // u8 * ptr; char thecwd[PATH_MAX]; if (getenv("AFL_LD_CALLER") != NULL) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 5d98d646..ee6d6de9 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -31,9 +31,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 6e2d7708..5fd60cd2 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -29,10 +29,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c index b5b8196d..087f18e8 100644 --- a/utils/afl_frida/afl-frida.c +++ b/utils/afl_frida/afl-frida.c @@ -153,7 +153,7 @@ static int enumerate_ranges(const GumRangeDetails *details, } -int main() { +int main(int argc, char** argv) { #ifndef __APPLE__ (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR @@ -164,105 +164,140 @@ int main() { // If there is just one function, then there is nothing to change // or add here. - void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); + void *dl = NULL; + if (argc > 2) { + dl = dlopen(argv[1], RTLD_LAZY); + } else { + dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); + } if (!dl) { - fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); + if (argc > 2) + fprintf(stderr, "Could not load %s\n", argv[1]); + else + fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); exit(-1); } - if (!(o_function = dlsym(dl, TARGET_FUNCTION))) { + if (argc > 2) + o_function = dlsym(dl, argv[2]); + else + o_function = dlsym(dl, TARGET_FUNCTION); + if (!o_function) { - fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); + if (argc > 2) + fprintf(stderr, "Could not find function %s\n", argv[2]); + else + fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); exit(-1); } // END STEP 2 - gum_init_embedded(); - if (!gum_stalker_is_supported()) { - - gum_deinit_embedded(); - return 1; - - } - - GumStalker *stalker = gum_stalker_new(); - - GumAddress base_address = gum_module_find_base_address(TARGET_LIBRARY); - GumMemoryRange code_range; - gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, - &code_range); - - guint64 code_start = code_range.base_address; - guint64 code_end = code_range.base_address + code_range.size; - range_t instr_range = {0, code_start, code_end}; - - printf("Frida instrumentation: base=0x%lx instrumenting=0x%lx-%lx\n", - base_address, code_start, code_end); - if (!code_start || !code_end) { - - fprintf(stderr, "Error: no valid memory address found for %s\n", - TARGET_LIBRARY); - exit(-1); - - } - - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, - &instr_range, NULL); - - // to ensure that the signatures are not optimized out - memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT) + 1); - memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR, - sizeof(AFL_DEFER_FORKSVR) + 1); - __afl_manual_init(); - - // - // any expensive target library initialization that has to be done just once - // - put that here - // - - gum_stalker_follow_me(stalker, transformer, NULL); - - while (__afl_persistent_loop(UINT32_MAX) != 0) { - - previous_pc = 0; // Required! - -#ifdef _DEBUG - fprintf(stderr, "CLIENT crc: %016llx len: %u\n", - hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len); - fprintf(stderr, "RECV:"); - for (int i = 0; i < *__afl_fuzz_len; i++) - fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); - fprintf(stderr, "\n"); -#endif - - // STEP 3: ensure the minimum length is present and setup the target - // function to fuzz. - - if (*__afl_fuzz_len > 0) { - - __afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate - (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len); - + if (!getenv("AFL_FRIDA_TEST_INPUT")) { + gum_init_embedded(); + if (!gum_stalker_is_supported()) { + + gum_deinit_embedded(); + return 1; + } + + GumStalker *stalker = gum_stalker_new(); + + GumAddress base_address; + if (argc > 2) + base_address = gum_module_find_base_address(argv[1]); + else + base_address = gum_module_find_base_address(TARGET_LIBRARY); + GumMemoryRange code_range; + if (argc > 2) + gum_module_enumerate_ranges(argv[1], GUM_PAGE_RX, enumerate_ranges, + &code_range); + else + gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, + &code_range); + + guint64 code_start = code_range.base_address; + guint64 code_end = code_range.base_address + code_range.size; + range_t instr_range = {0, code_start, code_end}; + + printf("Frida instrumentation: base=0x%lx instrumenting=0x%lx-%lx\n", + base_address, code_start, code_end); + if (!code_start || !code_end) { + + if (argc > 2) + fprintf(stderr, "Error: no valid memory address found for %s\n", + argv[1]); + else + fprintf(stderr, "Error: no valid memory address found for %s\n", + TARGET_LIBRARY); + exit(-1); + + } + + GumStalkerTransformer *transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, + &instr_range, NULL); + + // to ensure that the signatures are not optimized out + memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT) + 1); + memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR, + sizeof(AFL_DEFER_FORKSVR) + 1); + __afl_manual_init(); + + // + // any expensive target library initialization that has to be done just once + // - put that here + // + + gum_stalker_follow_me(stalker, transformer, NULL); + + while (__afl_persistent_loop(UINT32_MAX) != 0) { + + previous_pc = 0; // Required! + + #ifdef _DEBUG + fprintf(stderr, "CLIENT crc: %016llx len: %u\n", + hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len); + fprintf(stderr, "RECV:"); + for (int i = 0; i < *__afl_fuzz_len; i++) + fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); + fprintf(stderr, "\n"); + #endif + + // STEP 3: ensure the minimum length is present and setup the target + // function to fuzz. + + if (*__afl_fuzz_len > 0) { + + __afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate + (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + + // END STEP 3 + + } + + gum_stalker_unfollow_me(stalker); + + while (gum_stalker_garbage_collect(stalker)) + g_usleep(10000); + + g_object_unref(stalker); + g_object_unref(transformer); + gum_deinit_embedded(); - // END STEP 3 - + } else { + char buf[8*1024] = {0}; + int count = read(0, buf, sizeof(buf)); + buf[8*1024-1] = '\0'; + (*o_function)(buf, count); } - gum_stalker_unfollow_me(stalker); - - while (gum_stalker_garbage_collect(stalker)) - g_usleep(10000); - - g_object_unref(stalker); - g_object_unref(transformer); - gum_deinit_embedded(); - return 0; } diff --git a/utils/afl_frida/android/README.md b/utils/afl_frida/android/README.md new file mode 100644 index 00000000..044b48a1 --- /dev/null +++ b/utils/afl_frida/android/README.md @@ -0,0 +1 @@ +For android, frida-gum package (ex. https://github.com/frida/frida/releases/download/14.2.6/frida-gum-devkit-14.2.6-android-arm64.tar.xz) is needed to be extracted in the directory. diff --git a/utils/afl_frida/android/frida-gum-example.c b/utils/afl_frida/android/frida-gum-example.c new file mode 100644 index 00000000..14d98248 --- /dev/null +++ b/utils/afl_frida/android/frida-gum-example.c @@ -0,0 +1,130 @@ +/* + * Compile with: + * + * clang -fPIC -DANDROID -ffunction-sections -fdata-sections -Os -pipe -g3 frida-gum-example.c -o frida-gum-example -L. -lfrida-gum -llog -ldl -lm -pthread -Wl,--gc-sections,-z,noexecstack,-z,relro,-z,now -fuse-ld=gold -fuse-ld=gold -Wl,--icf=all + * + * Visit https://frida.re to learn more about Frida. + */ + +#include "frida-gum.h" + +#include <fcntl.h> +#include <unistd.h> + +typedef struct _ExampleListener ExampleListener; +typedef enum _ExampleHookId ExampleHookId; + +struct _ExampleListener +{ + GObject parent; + + guint num_calls; +}; + +enum _ExampleHookId +{ + EXAMPLE_HOOK_OPEN, + EXAMPLE_HOOK_CLOSE +}; + +static void example_listener_iface_init (gpointer g_iface, gpointer iface_data); + +#define EXAMPLE_TYPE_LISTENER (example_listener_get_type ()) +G_DECLARE_FINAL_TYPE (ExampleListener, example_listener, EXAMPLE, LISTENER, GObject) +G_DEFINE_TYPE_EXTENDED (ExampleListener, + example_listener, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE (GUM_TYPE_INVOCATION_LISTENER, + example_listener_iface_init)) + +int +main (int argc, + char * argv[]) +{ + GumInterceptor * interceptor; + GumInvocationListener * listener; + + gum_init_embedded (); + + interceptor = gum_interceptor_obtain (); + listener = g_object_new (EXAMPLE_TYPE_LISTENER, NULL); + + gum_interceptor_begin_transaction (interceptor); + gum_interceptor_attach (interceptor, + GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "open")), + listener, + GSIZE_TO_POINTER (EXAMPLE_HOOK_OPEN)); + gum_interceptor_attach (interceptor, + GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "close")), + listener, + GSIZE_TO_POINTER (EXAMPLE_HOOK_CLOSE)); + gum_interceptor_end_transaction (interceptor); + + close (open ("/etc/hosts", O_RDONLY)); + close (open ("/etc/fstab", O_RDONLY)); + + g_print ("[*] listener got %u calls\n", EXAMPLE_LISTENER (listener)->num_calls); + + gum_interceptor_detach (interceptor, listener); + + close (open ("/etc/hosts", O_RDONLY)); + close (open ("/etc/fstab", O_RDONLY)); + + g_print ("[*] listener still has %u calls\n", EXAMPLE_LISTENER (listener)->num_calls); + + g_object_unref (listener); + g_object_unref (interceptor); + + gum_deinit_embedded (); + + return 0; +} + +static void +example_listener_on_enter (GumInvocationListener * listener, + GumInvocationContext * ic) +{ + ExampleListener * self = EXAMPLE_LISTENER (listener); + ExampleHookId hook_id = GUM_IC_GET_FUNC_DATA (ic, ExampleHookId); + + switch (hook_id) + { + case EXAMPLE_HOOK_OPEN: + g_print ("[*] open(\"%s\")\n", (const gchar *) gum_invocation_context_get_nth_argument (ic, 0)); + break; + case EXAMPLE_HOOK_CLOSE: + g_print ("[*] close(%d)\n", GPOINTER_TO_INT (gum_invocation_context_get_nth_argument (ic, 0))); + break; + } + + self->num_calls++; +} + +static void +example_listener_on_leave (GumInvocationListener * listener, + GumInvocationContext * ic) +{ +} + +static void +example_listener_class_init (ExampleListenerClass * klass) +{ + (void) EXAMPLE_IS_LISTENER; + (void) glib_autoptr_cleanup_ExampleListener; +} + +static void +example_listener_iface_init (gpointer g_iface, + gpointer iface_data) +{ + GumInvocationListenerInterface * iface = g_iface; + + iface->on_enter = example_listener_on_enter; + iface->on_leave = example_listener_on_leave; +} + +static void +example_listener_init (ExampleListener * self) +{ +} diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c index 513dc8f2..fe225416 100644 --- a/utils/afl_network_proxy/afl-network-server.c +++ b/utils/afl_network_proxy/afl-network-server.c @@ -24,10 +24,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" |