/* * Configure entry-point, persistence etc. This will be what most * people want to do. */ const persistent_addr = DebugSymbol.fromName('main'); Afl.print(`persistent_addr: ${persistent_addr.address}`);
if (persistent_addr.address.equals(ptr(0))) { Afl.error('Cannot find symbol main'); }
/* Control instrumentation, you may want to do this too */ Afl.setInstrumentLibraries(); const mod = Process.findModuleByName("libc-2.31.so") Afl.addExcludedRange(mod.base, mod.size);
/* Some useful options to configure logging */ Afl.setStdOut("/tmp/stdout.txt"); Afl.setStdErr("/tmp/stderr.txt");
/* Show the address layout. Sometimes helpful */ Afl.setDebugMaps();
/* * If you are using these options, then things aren't going * very well for you. */ Afl.setInstrumentDebugFile("/tmp/instr.log"); Afl.setPrefetchDisable(); Afl.setInstrumentNoOptimize(); Afl.setInstrumentEnableTracing(); Afl.setInstrumentTracingUnique(); Afl.setStatsFile("/tmp/stats.txt"); Afl.setStatsInterval(1);
/* *ALWAYS* call this when you have finished all your configuration */ Afl.done(); Afl.print("done");
Stripped binaries
下面的例子是处理没符号或者导出表的二进制的情况:
1 2 3 4
constmodule = Process.getModuleByName('target.exe'); /* Hardcoded offset within the target image */ const address = module.base.add(0xdeadface); Afl.setPersistentAddress(address);
// we support three input cases if (buf[0] == '0') printf("Looks like a zero to me!\n"); elseif (buf[0] == '1') printf("Pretty sure that is a one!\n"); else printf("Neither one or zero? How quaint!\n");
}
intrun(char *file) {
int fd = -1; off_t len; char * buf = NULL; size_t n_read; int result = -1;
/* american fuzzy lop++ - a trivial program to test the build -------------------------------------------------------- Originally written by Michal Zalewski Copyright 2014 Google Inc. All rights reserved. Copyright 2019-2022 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0 */
/* * Don't you hate those contrived examples which CRC their data. We can use * FRIDA to patch this function out and always return success. Otherwise, we * could change it to actually correct the checksum. */ intcrc32_check(char * buf, int len) { if (len < sizeof(uint32_t)) { return0; } uint32_t expected = *(uint32_t *)&buf[len - sizeof(uint32_t)]; uint32_t calculated = crc32(buf, len - sizeof(uint32_t)); return expected == calculated; }
/* * So you've found a really boring bug in an earlier campaign which results in * a NULL dereference or something like that. That bug can get in the way, * causing the persistent loop to exit whenever it is triggered, and can also * cloud your output unnecessarily. Again, we can use FRIDA to patch it out. */ voidsome_boring_bug(char c) { switch (c) { case'A'...'Z': case'a'...'z': __builtin_trap(); break; } }
voidLLVMFuzzerTestOneInput(char *buf, int len) {
if (!crc32_check(buf, len)) return;
some_boring_bug(buf[0]);
if (buf[0] == '0') { printf("Looks like a zero to me!\n"); } elseif (buf[0] == '1') { printf("Pretty sure that is a one!\n"); } elseif (buf[0] == '2') { if (buf[1] == '3') { if (buf[2] == '4') { printf("Oh we, weren't expecting that!"); __builtin_trap(); } } } else printf("Neither one or zero? How quaint!\n");
}
intmain(int argc, char **argv) {
int fd = -1; off_t len; char * buf = NULL; size_t n_read; int result = -1;
最后注意:应保持forkserver父子进程的代码相同或forkserver每次产生的子进程代码相同,否则会产生难以调试的bug【原文: note that the same callback will be called when compiling instrumented code both in the child of the forkserver (as it is executed) and also in the parent of the forkserver (when prefetching is enabled) so that it can be inherited by the next forked child. It is VERY important that the same instructions be generated in both the parent and the child or if prefetching is disabled that the same instructions are generated every time the block is compiled. Failure to do so will likely lead to bugs which are incredibly difficult to diagnose. The code above only prints the instructions when running in the parent process (the one provided by Process.id when the JS script is executed).】
classAfl { /** * This is equivalent to setting a value in `AFL_FRIDA_EXCLUDE_RANGES`, * it takes as arguments a `NativePointer` and a `number`. It can be * called multiple times to exclude several ranges. */ staticaddExcludedRange(addressess, size) { Afl.jsApiAddExcludeRange(addressess, size); } /** * This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`, * it takes as arguments a `NativePointer` and a `number`. It can be * called multiple times to include several ranges. */ staticaddIncludedRange(addressess, size) { Afl.jsApiAddIncludeRange(addressess, size); } /** * This must always be called at the end of your script. This lets * FRIDA mode know that your configuration is finished and that * execution has reached the end of your script. Failure to call * this will result in a fatal error. */ staticdone() { Afl.jsApiDone(); } /** * This function can be called within your script to cause FRIDA * mode to trigger a fatal error. This is useful if for example you * discover a problem you weren't expecting and want everything to * stop. The user will need to enable `AFL_DEBUG_CHILD=1` to view * this error message. */ staticerror(msg) { const buf = Memory.allocUtf8String(msg); Afl.jsApiError(buf); } /** * Function used to provide access to `__afl_fuzz_ptr`, which contains the length of * fuzzing data when using in-memory test case fuzzing. */ staticgetAflFuzzLen() { returnAfl.jsApiGetSymbol("__afl_fuzz_len"); } /** * Function used to provide access to `__afl_fuzz_ptr`, which contains the fuzzing * data when using in-memory test case fuzzing. */ staticgetAflFuzzPtr() { returnAfl.jsApiGetSymbol("__afl_fuzz_ptr"); } /** * Print a message to the STDOUT. This should be preferred to * FRIDA's `console.log` since FRIDA will queue it's log messages. * If `console.log` is used in a callback in particular, then there * may no longer be a thread running to service this queue. */ staticprint(msg) { constSTDOUT_FILENO = 2; const log = `${msg}\n`; const buf = Memory.allocUtf8String(log); Afl.jsApiWrite(STDOUT_FILENO, buf, log.length); } /** * See `AFL_FRIDA_STALKER_NO_BACKPATCH`. */ staticsetBackpatchDisable() { Afl.jsApiSetBackpatchDisable(); } /** * See `AFL_FRIDA_DEBUG_MAPS`. */ staticsetDebugMaps() { Afl.jsApiSetDebugMaps(); } /** * This has the same effect as setting `AFL_ENTRYPOINT`, but has the * convenience of allowing you to use FRIDAs APIs to determine the * address you would like to configure, rather than having to grep * the output of `readelf` or something similarly ugly. This * function should be called with a `NativePointer` as its * argument. */ staticsetEntryPoint(address) { Afl.jsApiSetEntryPoint(address); } /** * Function used to enable in-memory test cases for fuzzing. */ staticsetInMemoryFuzzing() { Afl.jsApiAflSharedMemFuzzing.writeInt(1); } /** * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` * as an argument. */ staticsetInstrumentCoverageFile(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetInstrumentCoverageFile(buf); } /** * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as * an argument. */ staticsetInstrumentDebugFile(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetInstrumentDebugFile(buf); } /** * See `AFL_FRIDA_INST_TRACE`. */ staticsetInstrumentEnableTracing() { Afl.jsApiSetInstrumentTrace(); } /** * See `AFL_FRIDA_INST_JIT`. */ staticsetInstrumentJit() { Afl.jsApiSetInstrumentJit(); } /** * See `AFL_INST_LIBS`. */ staticsetInstrumentLibraries() { Afl.jsApiSetInstrumentLibraries(); } /** * See `AFL_FRIDA_INST_NO_OPTIMIZE` */ staticsetInstrumentNoOptimize() { Afl.jsApiSetInstrumentNoOptimize(); } /* * See `AFL_FRIDA_INST_SEED` */ staticsetInstrumentSeed(seed) { Afl.jsApiSetInstrumentSeed(seed); } /** * See `AFL_FRIDA_INST_TRACE_UNIQUE`. */ staticsetInstrumentTracingUnique() { Afl.jsApiSetInstrumentTraceUnique(); } /** * See `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE`. This function takes a single * `string` as an argument. */ staticsetInstrumentUnstableCoverageFile(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetInstrumentUnstableCoverageFile(buf); } /* * Set a callback to be called in place of the usual `main` function. This see * `Scripting.md` for details. */ staticsetJsMainHook(address) { Afl.jsApiSetJsMainHook(address); } /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * `NativePointer` should be provided as it's argument. */ staticsetPersistentAddress(address) { Afl.jsApiSetPersistentAddress(address); } /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a * `number` should be provided as it's argument. */ staticsetPersistentCount(count) { Afl.jsApiSetPersistentCount(count); } /** * See `AFL_FRIDA_PERSISTENT_DEBUG`. */ staticsetPersistentDebug() { Afl.jsApiSetPersistentDebug(); } /** * See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an * argument. See above for examples of use. */ staticsetPersistentHook(address) { Afl.jsApiSetPersistentHook(address); } /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a * `NativePointer` should be provided as it's argument. */ staticsetPersistentReturn(address) { Afl.jsApiSetPersistentReturn(address); } /** * See `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`. */ staticsetPrefetchBackpatchDisable() { Afl.jsApiSetPrefetchBackpatchDisable(); } /** * See `AFL_FRIDA_INST_NO_PREFETCH`. */ staticsetPrefetchDisable() { Afl.jsApiSetPrefetchDisable(); } /** * See `AFL_FRIDA_SECCOMP_FILE`. This function takes a single `string` as * an argument. */ staticsetSeccompFile(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetSeccompFile(buf); } /** * See `AFL_FRIDA_STALKER_ADJACENT_BLOCKS`. */ staticsetStalkerAdjacentBlocks(val) { Afl.jsApiSetStalkerAdjacentBlocks(val); } /* * Set a function to be called for each instruction which is instrumented * by AFL FRIDA mode. */ staticsetStalkerCallback(callback) { Afl.jsApiSetStalkerCallback(callback); } /** * See `AFL_FRIDA_STALKER_IC_ENTRIES`. */ staticsetStalkerIcEntries(val) { Afl.jsApiSetStalkerIcEntries(val); } /** * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as * an argument. */ staticsetStatsFile(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetStatsFile(buf); } /** * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an * argument */ staticsetStatsInterval(interval) { Afl.jsApiSetStatsInterval(interval); } /** * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as * an argument. */ staticsetStdErr(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetStdErr(buf); } /** * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as * an argument. */ staticsetStdOut(file) { const buf = Memory.allocUtf8String(file); Afl.jsApiSetStdOut(buf); } /** * See `AFL_FRIDA_TRACEABLE`. */ staticsetTraceable() { Afl.jsApiSetTraceable(); } staticjsApiGetFunction(name, retType, argTypes) { const addr = Afl.module.getExportByName(name); returnnewNativeFunction(addr, retType, argTypes); } staticjsApiGetSymbol(name) { returnAfl.module.getExportByName(name); } }