diff options
author | vanhauser-thc <vh@thc.org> | 2021-07-19 10:48:41 +0200 |
---|---|---|
committer | vanhauser-thc <vh@thc.org> | 2021-07-19 10:48:41 +0200 |
commit | cc57cc5f463e9b79980c2087d19b4a1e1360ec52 (patch) | |
tree | 69a89651deefc660b481e9c964f4cb97ab9073b6 /frida_mode/src | |
parent | 3d1cc8ec57f0bf07d7834b652ec2db24e7914624 (diff) | |
parent | c55f7af65700e3d11c368072d39ba6670efa477b (diff) | |
download | afl++-cc57cc5f463e9b79980c2087d19b4a1e1360ec52.tar.gz |
fix merge conflicts
Diffstat (limited to 'frida_mode/src')
-rw-r--r-- | frida_mode/src/asan/asan_arm32.c | 28 | ||||
-rw-r--r-- | frida_mode/src/cmplog/cmplog_arm32.c | 19 | ||||
-rw-r--r-- | frida_mode/src/ctx/ctx_arm32.c | 16 | ||||
-rw-r--r-- | frida_mode/src/ctx/ctx_arm64.c | 303 | ||||
-rw-r--r-- | frida_mode/src/intercept.c | 35 | ||||
-rw-r--r-- | frida_mode/src/js/api.js | 257 | ||||
-rw-r--r-- | frida_mode/src/js/js.c | 142 | ||||
-rw-r--r-- | frida_mode/src/js/js_api.c | 201 | ||||
-rw-r--r-- | frida_mode/src/stats/stats_arm32.c | 36 |
9 files changed, 1037 insertions, 0 deletions
diff --git a/frida_mode/src/asan/asan_arm32.c b/frida_mode/src/asan/asan_arm32.c new file mode 100644 index 00000000..f5fa4713 --- /dev/null +++ b/frida_mode/src/asan/asan_arm32.c @@ -0,0 +1,28 @@ +#include "frida-gumjs.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/cmplog/cmplog_arm32.c b/frida_mode/src/cmplog/cmplog_arm32.c new file mode 100644 index 00000000..ac703408 --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_arm32.c @@ -0,0 +1,19 @@ +#include "frida-gumjs.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/ctx/ctx_arm32.c b/frida_mode/src/ctx/ctx_arm32.c new file mode 100644 index 00000000..9fc70fb4 --- /dev/null +++ b/frida_mode/src/ctx/ctx_arm32.c @@ -0,0 +1,16 @@ +#include "frida-gumjs.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__arm__) + +gsize ctx_read_reg(GumArmCpuContext *ctx, arm_reg reg) { + + FATAL("ctx_read_reg unimplemented for this architecture"); + +} + +#endif + diff --git a/frida_mode/src/ctx/ctx_arm64.c b/frida_mode/src/ctx/ctx_arm64.c new file mode 100644 index 00000000..a735401b --- /dev/null +++ b/frida_mode/src/ctx/ctx_arm64.c @@ -0,0 +1,303 @@ +#include "frida-gumjs.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__aarch64__) + + #define ARM64_REG_8(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define ARM64_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define ARM64_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define ARM64_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +gsize ctx_read_reg(GumArm64CpuContext *ctx, arm64_reg reg) { + + switch (reg) { + + case ARM64_REG_WZR: + case ARM64_REG_XZR: + return 0; + + ARM64_REG_8(ARM64_REG_B0, ctx->x[0]) + ARM64_REG_8(ARM64_REG_B1, ctx->x[1]) + ARM64_REG_8(ARM64_REG_B2, ctx->x[2]) + ARM64_REG_8(ARM64_REG_B3, ctx->x[3]) + ARM64_REG_8(ARM64_REG_B4, ctx->x[4]) + ARM64_REG_8(ARM64_REG_B5, ctx->x[5]) + ARM64_REG_8(ARM64_REG_B6, ctx->x[6]) + ARM64_REG_8(ARM64_REG_B7, ctx->x[7]) + ARM64_REG_8(ARM64_REG_B8, ctx->x[8]) + ARM64_REG_8(ARM64_REG_B9, ctx->x[9]) + ARM64_REG_8(ARM64_REG_B10, ctx->x[10]) + ARM64_REG_8(ARM64_REG_B11, ctx->x[11]) + ARM64_REG_8(ARM64_REG_B12, ctx->x[12]) + ARM64_REG_8(ARM64_REG_B13, ctx->x[13]) + ARM64_REG_8(ARM64_REG_B14, ctx->x[14]) + ARM64_REG_8(ARM64_REG_B15, ctx->x[15]) + ARM64_REG_8(ARM64_REG_B16, ctx->x[16]) + ARM64_REG_8(ARM64_REG_B17, ctx->x[17]) + ARM64_REG_8(ARM64_REG_B18, ctx->x[18]) + ARM64_REG_8(ARM64_REG_B19, ctx->x[19]) + ARM64_REG_8(ARM64_REG_B20, ctx->x[20]) + ARM64_REG_8(ARM64_REG_B21, ctx->x[21]) + ARM64_REG_8(ARM64_REG_B22, ctx->x[22]) + ARM64_REG_8(ARM64_REG_B23, ctx->x[23]) + ARM64_REG_8(ARM64_REG_B24, ctx->x[24]) + ARM64_REG_8(ARM64_REG_B25, ctx->x[25]) + ARM64_REG_8(ARM64_REG_B26, ctx->x[26]) + ARM64_REG_8(ARM64_REG_B27, ctx->x[27]) + ARM64_REG_8(ARM64_REG_B28, ctx->x[28]) + ARM64_REG_8(ARM64_REG_B29, ctx->fp) + ARM64_REG_8(ARM64_REG_B30, ctx->lr) + ARM64_REG_8(ARM64_REG_B31, ctx->sp) + + ARM64_REG_16(ARM64_REG_H0, ctx->x[0]) + ARM64_REG_16(ARM64_REG_H1, ctx->x[1]) + ARM64_REG_16(ARM64_REG_H2, ctx->x[2]) + ARM64_REG_16(ARM64_REG_H3, ctx->x[3]) + ARM64_REG_16(ARM64_REG_H4, ctx->x[4]) + ARM64_REG_16(ARM64_REG_H5, ctx->x[5]) + ARM64_REG_16(ARM64_REG_H6, ctx->x[6]) + ARM64_REG_16(ARM64_REG_H7, ctx->x[7]) + ARM64_REG_16(ARM64_REG_H8, ctx->x[8]) + ARM64_REG_16(ARM64_REG_H9, ctx->x[9]) + ARM64_REG_16(ARM64_REG_H10, ctx->x[10]) + ARM64_REG_16(ARM64_REG_H11, ctx->x[11]) + ARM64_REG_16(ARM64_REG_H12, ctx->x[12]) + ARM64_REG_16(ARM64_REG_H13, ctx->x[13]) + ARM64_REG_16(ARM64_REG_H14, ctx->x[14]) + ARM64_REG_16(ARM64_REG_H15, ctx->x[15]) + ARM64_REG_16(ARM64_REG_H16, ctx->x[16]) + ARM64_REG_16(ARM64_REG_H17, ctx->x[17]) + ARM64_REG_16(ARM64_REG_H18, ctx->x[18]) + ARM64_REG_16(ARM64_REG_H19, ctx->x[19]) + ARM64_REG_16(ARM64_REG_H20, ctx->x[20]) + ARM64_REG_16(ARM64_REG_H21, ctx->x[21]) + ARM64_REG_16(ARM64_REG_H22, ctx->x[22]) + ARM64_REG_16(ARM64_REG_H23, ctx->x[23]) + ARM64_REG_16(ARM64_REG_H24, ctx->x[24]) + ARM64_REG_16(ARM64_REG_H25, ctx->x[25]) + ARM64_REG_16(ARM64_REG_H26, ctx->x[26]) + ARM64_REG_16(ARM64_REG_H27, ctx->x[27]) + ARM64_REG_16(ARM64_REG_H28, ctx->x[28]) + ARM64_REG_16(ARM64_REG_H29, ctx->fp) + ARM64_REG_16(ARM64_REG_H30, ctx->lr) + ARM64_REG_16(ARM64_REG_H31, ctx->sp) + + ARM64_REG_32(ARM64_REG_W0, ctx->x[0]) + ARM64_REG_32(ARM64_REG_W1, ctx->x[1]) + ARM64_REG_32(ARM64_REG_W2, ctx->x[2]) + ARM64_REG_32(ARM64_REG_W3, ctx->x[3]) + ARM64_REG_32(ARM64_REG_W4, ctx->x[4]) + ARM64_REG_32(ARM64_REG_W5, ctx->x[5]) + ARM64_REG_32(ARM64_REG_W6, ctx->x[6]) + ARM64_REG_32(ARM64_REG_W7, ctx->x[7]) + ARM64_REG_32(ARM64_REG_W8, ctx->x[8]) + ARM64_REG_32(ARM64_REG_W9, ctx->x[9]) + ARM64_REG_32(ARM64_REG_W10, ctx->x[10]) + ARM64_REG_32(ARM64_REG_W11, ctx->x[11]) + ARM64_REG_32(ARM64_REG_W12, ctx->x[12]) + ARM64_REG_32(ARM64_REG_W13, ctx->x[13]) + ARM64_REG_32(ARM64_REG_W14, ctx->x[14]) + ARM64_REG_32(ARM64_REG_W15, ctx->x[15]) + ARM64_REG_32(ARM64_REG_W16, ctx->x[16]) + ARM64_REG_32(ARM64_REG_W17, ctx->x[17]) + ARM64_REG_32(ARM64_REG_W18, ctx->x[18]) + ARM64_REG_32(ARM64_REG_W19, ctx->x[19]) + ARM64_REG_32(ARM64_REG_W20, ctx->x[20]) + ARM64_REG_32(ARM64_REG_W21, ctx->x[21]) + ARM64_REG_32(ARM64_REG_W22, ctx->x[22]) + ARM64_REG_32(ARM64_REG_W23, ctx->x[23]) + ARM64_REG_32(ARM64_REG_W24, ctx->x[24]) + ARM64_REG_32(ARM64_REG_W25, ctx->x[25]) + ARM64_REG_32(ARM64_REG_W26, ctx->x[26]) + ARM64_REG_32(ARM64_REG_W27, ctx->x[27]) + ARM64_REG_32(ARM64_REG_W28, ctx->x[28]) + ARM64_REG_32(ARM64_REG_W29, ctx->fp) + ARM64_REG_32(ARM64_REG_W30, ctx->lr) + + ARM64_REG_64(ARM64_REG_X0, ctx->x[0]) + ARM64_REG_64(ARM64_REG_X1, ctx->x[1]) + ARM64_REG_64(ARM64_REG_X2, ctx->x[2]) + ARM64_REG_64(ARM64_REG_X3, ctx->x[3]) + ARM64_REG_64(ARM64_REG_X4, ctx->x[4]) + ARM64_REG_64(ARM64_REG_X5, ctx->x[5]) + ARM64_REG_64(ARM64_REG_X6, ctx->x[6]) + ARM64_REG_64(ARM64_REG_X7, ctx->x[7]) + ARM64_REG_64(ARM64_REG_X8, ctx->x[8]) + ARM64_REG_64(ARM64_REG_X9, ctx->x[9]) + ARM64_REG_64(ARM64_REG_X10, ctx->x[10]) + ARM64_REG_64(ARM64_REG_X11, ctx->x[11]) + ARM64_REG_64(ARM64_REG_X12, ctx->x[12]) + ARM64_REG_64(ARM64_REG_X13, ctx->x[13]) + ARM64_REG_64(ARM64_REG_X14, ctx->x[14]) + ARM64_REG_64(ARM64_REG_X15, ctx->x[15]) + ARM64_REG_64(ARM64_REG_X16, ctx->x[16]) + ARM64_REG_64(ARM64_REG_X17, ctx->x[17]) + ARM64_REG_64(ARM64_REG_X18, ctx->x[18]) + ARM64_REG_64(ARM64_REG_X19, ctx->x[19]) + ARM64_REG_64(ARM64_REG_X20, ctx->x[20]) + ARM64_REG_64(ARM64_REG_X21, ctx->x[21]) + ARM64_REG_64(ARM64_REG_X22, ctx->x[22]) + ARM64_REG_64(ARM64_REG_X23, ctx->x[23]) + ARM64_REG_64(ARM64_REG_X24, ctx->x[24]) + ARM64_REG_64(ARM64_REG_X25, ctx->x[25]) + ARM64_REG_64(ARM64_REG_X26, ctx->x[26]) + ARM64_REG_64(ARM64_REG_X27, ctx->x[27]) + ARM64_REG_64(ARM64_REG_X28, ctx->x[28]) + ARM64_REG_64(ARM64_REG_FP, ctx->fp) + ARM64_REG_64(ARM64_REG_LR, ctx->lr) + ARM64_REG_64(ARM64_REG_SP, ctx->sp) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +size_t ctx_get_size(const cs_insn *instr, cs_arm64_op *operand) { + + uint8_t num_registers; + uint8_t count_byte; + char vas_digit; + size_t mnemonic_len; + + switch (instr->id) { + + case ARM64_INS_STP: + case ARM64_INS_STXP: + case ARM64_INS_STNP: + case ARM64_INS_STLXP: + case ARM64_INS_LDP: + case ARM64_INS_LDXP: + case ARM64_INS_LDNP: + num_registers = 2; + break; + default: + num_registers = 1; + break; + + } + + mnemonic_len = strlen(instr->mnemonic); + if (mnemonic_len == 0) { FATAL("No mnemonic found"); }; + + char last = instr->mnemonic[mnemonic_len - 1]; + switch (last) { + + case 'b': + return 1; + case 'h': + return 2; + case 'w': + return 4 * num_registers; + + } + + if (operand->vas == ARM64_VAS_INVALID) { + + if (operand->type == ARM64_OP_REG) { + + switch (operand->reg) { + + case ARM64_REG_WZR: + case ARM64_REG_WSP: + case ARM64_REG_W0 ... ARM64_REG_W30: + case ARM64_REG_S0 ... ARM64_REG_S31: + return 4 * num_registers; + case ARM64_REG_D0 ... ARM64_REG_D31: + return 8 * num_registers; + case ARM64_REG_Q0 ... ARM64_REG_Q31: + return 16; + default: + return 8 * num_registers; + ; + + } + + } + + return 8 * num_registers; + + } + + if (g_str_has_prefix(instr->mnemonic, "st") || + g_str_has_prefix(instr->mnemonic, "ld")) { + + if (mnemonic_len < 3) { + + FATAL("VAS Mnemonic too short: %s\n", instr->mnemonic); + + } + + vas_digit = instr->mnemonic[2]; + if (vas_digit < '0' || vas_digit > '9') { + + FATAL("VAS Mnemonic digit out of range: %s\n", instr->mnemonic); + + } + + count_byte = vas_digit - '0'; + + } else { + + count_byte = 1; + + } + + switch (operand->vas) { + + case ARM64_VAS_1B: + return 1 * count_byte; + case ARM64_VAS_1H: + return 2 * count_byte; + case ARM64_VAS_4B: + case ARM64_VAS_1S: + case ARM64_VAS_1D: + case ARM64_VAS_2H: + return 4 * count_byte; + case ARM64_VAS_8B: + case ARM64_VAS_4H: + case ARM64_VAS_2S: + case ARM64_VAS_2D: + case ARM64_VAS_1Q: + return 8 * count_byte; + case ARM64_VAS_8H: + case ARM64_VAS_4S: + case ARM64_VAS_16B: + return 16 * count_byte; + default: + FATAL("Unexpected VAS type: %s %d", instr->mnemonic, operand->vas); + + } + +} + +#endif + diff --git a/frida_mode/src/intercept.c b/frida_mode/src/intercept.c new file mode 100644 index 00000000..ed8d27bd --- /dev/null +++ b/frida_mode/src/intercept.c @@ -0,0 +1,35 @@ +#include "frida-gumjs.h" + +#include "debug.h" + +#include "intercept.h" + +void intercept_hook(void *address, gpointer replacement, gpointer user_data) { + + GumInterceptor *interceptor = gum_interceptor_obtain(); + gum_interceptor_begin_transaction(interceptor); + GumReplaceReturn ret = + gum_interceptor_replace(interceptor, address, replacement, user_data); + if (ret != GUM_REPLACE_OK) { FATAL("gum_interceptor_attach: %d", ret); } + gum_interceptor_end_transaction(interceptor); + +} + +void intercept_unhook(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 intercept_unhook_self(void) { + + GumInvocationContext *ctx = gum_interceptor_get_current_invocation(); + intercept_unhook(ctx->function); + +} + diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js new file mode 100644 index 00000000..b8f2d39a --- /dev/null +++ b/frida_mode/src/js/api.js @@ -0,0 +1,257 @@ +"use strict"; +class Afl { + /** + * 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. + */ + static addExcludedRange(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. + */ + static addIncludedRange(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. + */ + static done() { + 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. + */ + static error(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. + */ + static getAflFuzzLen() { + return Afl.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. + */ + static getAflFuzzPtr() { + return Afl.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. + */ + static print(msg) { + const STDOUT_FILENO = 2; + const log = `${msg}\n`; + const buf = Memory.allocUtf8String(log); + Afl.jsApiWrite(STDOUT_FILENO, buf, log.length); + } + /** + * See `AFL_FRIDA_DEBUG_MAPS`. + */ + static setDebugMaps() { + 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. + */ + static setEntryPoint(address) { + Afl.jsApiSetEntryPoint(address); + } + /** + * Function used to enable in-memory test cases for fuzzing. + */ + static setInMemoryFuzzing() { + Afl.jsApiAflSharedMemFuzzing.writeInt(1); + } + /** + * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as + * an argument. + */ + static setInstrumentDebugFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentDebugFile(buf); + } + /** + * See `AFL_FRIDA_INST_TRACE`. + */ + static setInstrumentEnableTracing() { + Afl.jsApiSetInstrumentTrace(); + } + /** + * See `AFL_FRIDA_INST_JIT`. + */ + static setInstrumentJit() { + Afl.jsApiSetInstrumentJit(); + } + /** + * See `AFL_INST_LIBS`. + */ + static setInstrumentLibraries() { + Afl.jsApiSetInstrumentLibraries(); + } + /** + * See `AFL_FRIDA_INST_NO_OPTIMIZE` + */ + static setInstrumentNoOptimize() { + Afl.jsApiSetInstrumentNoOptimize(); + } + /* + * See `AFL_FRIDA_INST_SEED` + */ + static setInstrumentSeed(seed) { + Afl.jsApiSetInstrumentSeed(seed); + } + /** + * See `AFL_FRIDA_INST_TRACE_UNIQUE`. + */ + static setInstrumentTracingUnique() { + Afl.jsApiSetInstrumentTraceUnique(); + } + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a + * `NativePointer` should be provided as it's argument. + */ + static setPersistentAddress(address) { + Afl.jsApiSetPersistentAddress(address); + } + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a + * `number` should be provided as it's argument. + */ + static setPersistentCount(count) { + Afl.jsApiSetPersistentCount(count); + } + /** + * See `AFL_FRIDA_PERSISTENT_DEBUG`. + */ + static setPersistentDebug() { + Afl.jsApiSetPersistentDebug(); + } + /** + * See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an + * argument. See above for examples of use. + */ + static setPersistentHook(address) { + Afl.jsApiSetPersistentHook(address); + } + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a + * `NativePointer` should be provided as it's argument. + */ + static setPersistentReturn(address) { + Afl.jsApiSetPersistentReturn(address); + } + /** + * See `AFL_FRIDA_INST_NO_PREFETCH`. + */ + static setPrefetchDisable() { + Afl.jsApiSetPrefetchDisable(); + } + /* + * Set a function to be called for each instruction which is instrumented + * by AFL FRIDA mode. + */ + static setStalkerCallback(callback) { + Afl.jsApiSetStalkerCallback(callback); + } + /** + * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as + * an argument. + */ + static setStatsFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStatsFile(buf); + } + /** + * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an + * argument + */ + static setStatsInterval(interval) { + Afl.jsApiSetStatsInterval(interval); + } + /** + * See `AFL_FRIDA_STATS_TRANSITIONS` + */ + static setStatsTransitions() { + Afl.jsApiSetStatsTransitions(); + } + /** + * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as + * an argument. + */ + static setStdErr(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdErr(buf); + } + /** + * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as + * an argument. + */ + static setStdOut(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdOut(buf); + } + static jsApiGetFunction(name, retType, argTypes) { + const addr = Afl.module.getExportByName(name); + return new NativeFunction(addr, retType, argTypes); + } + static jsApiGetSymbol(name) { + return Afl.module.getExportByName(name); + } +} +/** + * Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode + * implementation). + */ +Afl.module = Process.getModuleByName("afl-frida-trace.so"); +Afl.jsApiAddExcludeRange = Afl.jsApiGetFunction("js_api_add_exclude_range", "void", ["pointer", "size_t"]); +Afl.jsApiAddIncludeRange = Afl.jsApiGetFunction("js_api_add_include_range", "void", ["pointer", "size_t"]); +Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing"); +Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []); +Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]); +Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []); +Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]); +Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]); +Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []); +Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []); +Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []); +Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]); +Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []); +Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []); +Afl.jsApiSetPersistentAddress = Afl.jsApiGetFunction("js_api_set_persistent_address", "void", ["pointer"]); +Afl.jsApiSetPersistentCount = Afl.jsApiGetFunction("js_api_set_persistent_count", "void", ["uint64"]); +Afl.jsApiSetPersistentDebug = Afl.jsApiGetFunction("js_api_set_persistent_debug", "void", []); +Afl.jsApiSetPersistentHook = Afl.jsApiGetFunction("js_api_set_persistent_hook", "void", ["pointer"]); +Afl.jsApiSetPersistentReturn = Afl.jsApiGetFunction("js_api_set_persistent_return", "void", ["pointer"]); +Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []); +Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]); +Afl.jsApiSetStatsFile = Afl.jsApiGetFunction("js_api_set_stats_file", "void", ["pointer"]); +Afl.jsApiSetStatsInterval = Afl.jsApiGetFunction("js_api_set_stats_interval", "void", ["uint64"]); +Afl.jsApiSetStatsTransitions = Afl.jsApiGetFunction("js_api_set_stats_transitions", "void", []); +Afl.jsApiSetStdErr = Afl.jsApiGetFunction("js_api_set_stderr", "void", ["pointer"]); +Afl.jsApiSetStdOut = Afl.jsApiGetFunction("js_api_set_stdout", "void", ["pointer"]); +Afl.jsApiWrite = new NativeFunction( +/* tslint:disable-next-line:no-null-keyword */ +Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]); diff --git a/frida_mode/src/js/js.c b/frida_mode/src/js/js.c new file mode 100644 index 00000000..e3cd4933 --- /dev/null +++ b/frida_mode/src/js/js.c @@ -0,0 +1,142 @@ +#include "frida-gumjs.h" + +#include "debug.h" + +#include "js.h" +#include "util.h" + +static char * js_script = NULL; +gboolean js_done = FALSE; +js_api_stalker_callback_t js_user_callback = NULL; + +static gchar * filename = "afl.js"; +static gchar * contents; +static GumScriptBackend * backend; +static GCancellable * cancellable = NULL; +static GError * error = NULL; +static GumScript * script; +static GumScriptScheduler *scheduler; +static GMainContext * context; +static GMainLoop * main_loop; + +static void js_msg(GumScript *script, const gchar *message, GBytes *data, + gpointer user_data) { + + UNUSED_PARAMETER(script); + UNUSED_PARAMETER(data); + UNUSED_PARAMETER(user_data); + OKF("%s", message); + +} + +void js_config(void) { + + js_script = getenv("AFL_FRIDA_JS_SCRIPT"); + +} + +static gchar *js_get_script() { + + gsize length; + if (js_script != NULL) { filename = js_script; } + + filename = g_canonicalize_filename(filename, g_get_current_dir()); + + if (!g_file_get_contents(filename, &contents, &length, NULL)) { + + if (js_script == NULL) { + + return NULL; + + } else { + + FATAL("Could not load script file: %s", filename); + + } + + } else { + + OKF("Loaded AFL script: %s, %" G_GSIZE_MODIFIER "d bytes", filename, + length); + + gchar *source = g_malloc0(api_js_len + length + 1); + memcpy(source, api_js, api_js_len); + memcpy(&source[api_js_len], contents, length); + + return source; + + } + +} + +static void js_print_script(gchar *source) { + + gchar **split = g_strsplit(source, "\n", 0); + + for (size_t i = 0; split[i] != NULL; i++) { + + OKF("%3" G_GSIZE_MODIFIER "d. %s", i + 1, split[i]); + + } + + g_strfreev(split); + +} + +static void load_cb(GObject *source_object, GAsyncResult *result, + gpointer user_data) { + + UNUSED_PARAMETER(source_object); + UNUSED_PARAMETER(user_data); + gum_script_load_finish(script, result); + if (error != NULL) { FATAL("Failed to load script - %s", error->message); } + +} + +static void create_cb(GObject *source_object, GAsyncResult *result, + gpointer user_data) { + + UNUSED_PARAMETER(source_object); + UNUSED_PARAMETER(user_data); + script = gum_script_backend_create_finish(backend, result, &error); + if (error != NULL) { FATAL("Failed to create script: %s", error->message); } + + gum_script_set_message_handler(script, js_msg, NULL, NULL); + + gum_script_load(script, cancellable, load_cb, NULL); + +} + +void js_start(void) { + + gchar *source = js_get_script(); + if (source == NULL) { return; } + js_print_script(source); + + scheduler = gum_script_backend_get_scheduler(); + gum_script_scheduler_disable_background_thread(scheduler); + + backend = gum_script_backend_obtain_qjs(); + + context = gum_script_scheduler_get_js_context(scheduler); + main_loop = g_main_loop_new(context, true); + g_main_context_push_thread_default(context); + + gum_script_backend_create(backend, "example", source, cancellable, create_cb, + &error); + + while (g_main_context_pending(context)) + g_main_context_iteration(context, FALSE); + + if (!js_done) { FATAL("Script didn't call Afl.done()"); } + +} + +gboolean js_stalker_callback(const cs_insn *insn, gboolean begin, + gboolean excluded, GumStalkerOutput *output) { + + if (js_user_callback == NULL) { return TRUE; } + return js_user_callback(insn, begin, excluded, output); + +} + diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c new file mode 100644 index 00000000..930a6dc0 --- /dev/null +++ b/frida_mode/src/js/js_api.c @@ -0,0 +1,201 @@ +#include "debug.h" + +#include "entry.h" +#include "instrument.h" +#include "js.h" +#include "output.h" +#include "persistent.h" +#include "prefetch.h" +#include "ranges.h" +#include "stats.h" +#include "util.h" +__attribute__((visibility("default"))) void js_api_done() { + + js_done = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_error(char *msg) { + + FATAL("%s", msg); + +} + +__attribute__((visibility("default"))) void js_api_set_entrypoint( + void *address) { + + if (address == NULL) { + + js_api_error("js_api_set_entrypoint called with NULL"); + + } + + entry_point = GPOINTER_TO_SIZE(address); + +} + +__attribute__((visibility("default"))) void js_api_set_persistent_address( + void *address) { + + if (address == NULL) { + + js_api_error("js_api_set_persistent_address called with NULL"); + + } + + persistent_start = GPOINTER_TO_SIZE(address); + +} + +__attribute__((visibility("default"))) void js_api_set_persistent_return( + void *address) { + + if (address == NULL) { + + js_api_error("js_api_set_persistent_return called with NULL"); + + } + + persistent_ret = GPOINTER_TO_SIZE(address); + +} + +__attribute__((visibility("default"))) void js_api_set_persistent_count( + uint64_t count) { + + persistent_count = count; + +} + +__attribute__((visibility("default"))) void js_api_set_persistent_debug() { + + persistent_debug = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_set_debug_maps() { + + ranges_debug_maps = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_add_include_range( + void *address, gsize size) { + + GumMemoryRange range = {.base_address = GUM_ADDRESS(address), .size = size}; + ranges_add_include(&range); + +} + +__attribute__((visibility("default"))) void js_api_add_exclude_range( + void *address, gsize size) { + + GumMemoryRange range = {.base_address = GUM_ADDRESS(address), .size = size}; + ranges_add_exclude(&range); + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_jit() { + + ranges_inst_jit = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_libraries() { + + ranges_inst_libs = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_debug_file( + char *path) { + + instrument_debug_filename = g_strdup(path); + +} + +__attribute__((visibility("default"))) void js_api_set_prefetch_disable(void) { + + prefetch_enable = FALSE; + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize( + void) { + + instrument_optimize = FALSE; + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_seed( + guint64 seed) { + + instrument_use_fixed_seed = TRUE; + instrument_fixed_seed = seed; + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_trace(void) { + + instrument_tracing = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_set_instrument_trace_unique( + void) { + + instrument_unique = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_set_stdout(char *file) { + + output_stdout = g_strdup(file); + +} + +__attribute__((visibility("default"))) void js_api_set_stderr(char *file) { + + output_stderr = g_strdup(file); + +} + +__attribute__((visibility("default"))) void js_api_set_stats_file(char *file) { + + stats_filename = g_strdup(file); + +} + +__attribute__((visibility("default"))) void js_api_set_stats_interval( + uint64_t interval) { + + stats_interval = interval; + +} + +__attribute__((visibility("default"))) void js_api_set_stats_transitions() { + + stats_transitions = TRUE; + +} + +__attribute__((visibility("default"))) void js_api_set_persistent_hook( + void *address) { + + if (address == NULL) { + + js_api_error("js_api_set_persistent_hook called with NULL"); + + } + + persistent_hook = address; + +} + +__attribute__((visibility("default"))) void js_api_set_stalker_callback( + const js_api_stalker_callback_t callback) { + + js_user_callback = callback; + +} + diff --git a/frida_mode/src/stats/stats_arm32.c b/frida_mode/src/stats/stats_arm32.c new file mode 100644 index 00000000..71953af3 --- /dev/null +++ b/frida_mode/src/stats/stats_arm32.c @@ -0,0 +1,36 @@ +#include "frida-gumjs.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 + |