mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-10 17:21:33 +00:00
Merge pull request #1075 from WorksButNotTested/test
Various New Features & Fixes
This commit is contained in:
commit
ca9c87dd45
@ -83,16 +83,7 @@ ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
ifeq "$(ARCH)" "arm64"
|
||||
# 15.0.0 Not released for aarch64 yet
|
||||
GUM_DEVKIT_VERSION=14.2.18
|
||||
else
|
||||
ifeq "$(ARCH)" "armhf"
|
||||
GUM_DEVKIT_VERSION=14.2.18
|
||||
else
|
||||
GUM_DEVKIT_VERSION=15.0.0
|
||||
endif
|
||||
endif
|
||||
GUM_DEVKIT_VERSION=15.0.16
|
||||
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
|
||||
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
|
||||
|
||||
|
@ -162,7 +162,12 @@ 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.
|
||||
them and they be inherited by the next child on fork, implies
|
||||
`AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`.
|
||||
* `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH` - Disable prefetching of stalker
|
||||
backpatching information. By default the child will report applied backpatches
|
||||
to the parent so that they can be applied and then be inherited by the next
|
||||
child on fork.
|
||||
* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to
|
||||
generate block (and hence edge) IDs. Setting this to a constant value may be
|
||||
useful for debugging purposes, e.g. investigating unstable edges.
|
||||
@ -189,6 +194,9 @@ gdb \
|
||||
--args <my-executable> [my arguments]
|
||||
|
||||
```
|
||||
* `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries
|
||||
stored along-side branch instructions which provide a cache to avoid having to
|
||||
call back into FRIDA to find the next block. Default is 32.
|
||||
* `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
|
||||
@ -198,67 +206,70 @@ 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
|
||||
Time 2021-07-21 11:45:49
|
||||
Elapsed 1 seconds
|
||||
|
||||
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%)
|
||||
Transitions cumulative delta
|
||||
----------- ---------- -----
|
||||
total 753619 17645
|
||||
call_imm 9193 ( 1.22%) 344 ( 1.95%) [ 344/s]
|
||||
call_reg 0 ( 0.00%) 0 ( 0.00%) [ 0/s]
|
||||
call_mem 0 ( 0.00%) 0 ( 0.00%) [ 0/s]
|
||||
ret_slow_path 67974 ( 9.02%) 2988 (16.93%) [ 2988/s]
|
||||
post_call_invoke 7996 ( 1.06%) 299 ( 1.69%) [ 299/s]
|
||||
excluded_call_imm 3804 ( 0.50%) 200 ( 1.13%) [ 200/s]
|
||||
jmp_imm 5445 ( 0.72%) 255 ( 1.45%) [ 255/s]
|
||||
jmp_reg 42081 ( 5.58%) 1021 ( 5.79%) [ 1021/s]
|
||||
jmp_mem 578092 (76.71%) 10956 (62.09%) [ 10956/s]
|
||||
jmp_cond_imm 38951 ( 5.17%) 1579 ( 8.95%) [ 1579/s]
|
||||
jmp_cond_mem 0 ( 0.00%) 0 ( 0.00%) [ 0/s]
|
||||
jmp_cond_reg 0 ( 0.00%) 0 ( 0.00%) [ 0/s]
|
||||
jmp_cond_jcxz 0 ( 0.00%) 0 ( 0.00%) [ 0/s]
|
||||
jmp_continuation 84 ( 0.01%) 3 ( 0.02%) [ 3/s]
|
||||
|
||||
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%)
|
||||
Instrumentation
|
||||
---------------
|
||||
Instructions 7907
|
||||
Blocks 1764
|
||||
Avg Instructions / Block 4
|
||||
|
||||
Rip Relative: 247 (0.00%)
|
||||
|
||||
EOB Instructions
|
||||
----------------
|
||||
Total 1763 (22.30%)
|
||||
Call Immediates 358 ( 4.53%)
|
||||
Call Immediates Excluded 74 ( 0.94%)
|
||||
Call Register 0 ( 0.00%)
|
||||
Call Memory 0 ( 0.00%)
|
||||
Jump Immediates 176 ( 2.23%)
|
||||
Jump Register 8 ( 0.10%)
|
||||
Jump Memory 10 ( 0.13%)
|
||||
Conditional Jump Immediates 1051 (13.29%)
|
||||
Conditional Jump CX Immediate 0 ( 0.00%)
|
||||
Conditional Jump Register 0 ( 0.00%)
|
||||
Conditional Jump Memory 0 ( 0.00%)
|
||||
Returns 160 ( 2.02%)
|
||||
|
||||
|
||||
Relocated Instructions
|
||||
----------------------
|
||||
Total 232 ( 2.93%)
|
||||
addsd 2 ( 0.86%)
|
||||
cmp 46 (19.83%)
|
||||
comisd 2 ( 0.86%)
|
||||
divsd 2 ( 0.86%)
|
||||
divss 2 ( 0.86%)
|
||||
lea 142 (61.21%)
|
||||
mov 32 (13.79%)
|
||||
movsd 2 ( 0.86%)
|
||||
ucomisd 2 ( 0.86%)
|
||||
```
|
||||
* `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.
|
||||
|
@ -80,7 +80,6 @@ Afl.setInstrumentEnableTracing();
|
||||
Afl.setInstrumentTracingUnique();
|
||||
Afl.setStatsFile("/tmp/stats.txt");
|
||||
Afl.setStatsInterval(1);
|
||||
Afl.setStatsTransitions();
|
||||
|
||||
/* *ALWAYS* call this when you have finished all your configuration */
|
||||
Afl.done();
|
||||
@ -833,13 +832,6 @@ class Afl {
|
||||
Afl.jsApiSetStatsInterval(interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_STATS_TRANSITIONS`
|
||||
*/
|
||||
public static setStatsTransitions(): void {
|
||||
Afl.jsApiSetStatsTransitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
|
||||
* an argument.
|
||||
|
@ -23,11 +23,11 @@
|
||||
js_api_set_persistent_debug;
|
||||
js_api_set_persistent_hook;
|
||||
js_api_set_persistent_return;
|
||||
js_api_set_prefetch_backpatch_disable;
|
||||
js_api_set_prefetch_disable;
|
||||
js_api_set_stalker_callback;
|
||||
js_api_set_stats_file;
|
||||
js_api_set_stats_interval;
|
||||
js_api_set_stats_transitions;
|
||||
js_api_set_stderr;
|
||||
js_api_set_stdout;
|
||||
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
extern guint64 entry_point;
|
||||
extern gboolean entry_reached;
|
||||
extern gboolean entry_compiled;
|
||||
extern gboolean entry_run;
|
||||
|
||||
void entry_config(void);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
extern gboolean prefetch_enable;
|
||||
extern gboolean prefetch_backpatch;
|
||||
|
||||
void prefetch_config(void);
|
||||
void prefetch_init(void);
|
||||
|
@ -10,7 +10,7 @@ extern gboolean ranges_inst_jit;
|
||||
void ranges_config(void);
|
||||
void ranges_init(void);
|
||||
|
||||
gboolean range_is_excluded(gpointer address);
|
||||
gboolean range_is_excluded(GumAddress address);
|
||||
|
||||
void ranges_exclude();
|
||||
|
||||
|
@ -3,11 +3,15 @@
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
extern guint stalker_ic_entries;
|
||||
|
||||
void stalker_config(void);
|
||||
void stalker_init(void);
|
||||
GumStalker *stalker_get(void);
|
||||
void stalker_start(void);
|
||||
void stalker_trust(void);
|
||||
|
||||
GumStalkerObserver *stalker_get_observer(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -5,30 +5,56 @@
|
||||
|
||||
typedef struct {
|
||||
|
||||
guint64 num_blocks;
|
||||
guint64 num_instructions;
|
||||
guint64 stats_last_time;
|
||||
guint64 stats_idx;
|
||||
guint64 transitions_idx;
|
||||
guint64 stats_time;
|
||||
guint64 total;
|
||||
guint64 call_imm;
|
||||
guint64 call_reg;
|
||||
guint64 call_mem;
|
||||
guint64 excluded_call_reg;
|
||||
guint64 ret_slow_path;
|
||||
guint64 ret;
|
||||
guint64 post_call_invoke;
|
||||
guint64 excluded_call_imm;
|
||||
guint64 jmp_imm;
|
||||
guint64 jmp_reg;
|
||||
guint64 jmp_mem;
|
||||
guint64 jmp_cond_imm;
|
||||
guint64 jmp_cond_mem;
|
||||
guint64 jmp_cond_reg;
|
||||
guint64 jmp_cond_jcxz;
|
||||
guint64 jmp_cond_cc;
|
||||
guint64 jmp_cond_cbz;
|
||||
guint64 jmp_cond_cbnz;
|
||||
guint64 jmp_cond_tbz;
|
||||
guint64 jmp_cond_tbnz;
|
||||
guint64 jmp_continuation;
|
||||
|
||||
} stats_data_header_t;
|
||||
} stats_t;
|
||||
|
||||
extern stats_data_header_t *stats_data;
|
||||
typedef struct {
|
||||
|
||||
extern char * stats_filename;
|
||||
extern guint64 stats_interval;
|
||||
extern gboolean stats_transitions;
|
||||
/* transitions */
|
||||
stats_t curr;
|
||||
stats_t prev;
|
||||
|
||||
} stats_data_t;
|
||||
|
||||
#define GUM_TYPE_AFL_STALKER_STATS (gum_afl_stalker_stats_get_type())
|
||||
G_DECLARE_FINAL_TYPE(GumAflStalkerStats, gum_afl_stalker_stats, GUM,
|
||||
AFL_STALKER_STATS, GObject)
|
||||
|
||||
extern char * stats_filename;
|
||||
extern guint64 stats_interval;
|
||||
|
||||
void stats_config(void);
|
||||
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);
|
||||
void stats_on_fork(void);
|
||||
void starts_arch_init(void);
|
||||
void stats_collect_arch(const cs_insn *instr, gboolean begin);
|
||||
void stats_write_arch(stats_data_t *data);
|
||||
void stats_on_fork(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "debug.h"
|
||||
@ -13,7 +15,8 @@
|
||||
extern void __afl_manual_init();
|
||||
|
||||
guint64 entry_point = 0;
|
||||
gboolean entry_reached = FALSE;
|
||||
gboolean entry_compiled = FALSE;
|
||||
gboolean entry_run = FALSE;
|
||||
|
||||
static void entry_launch(void) {
|
||||
|
||||
@ -21,7 +24,7 @@ static void entry_launch(void) {
|
||||
__afl_manual_init();
|
||||
|
||||
/* Child here */
|
||||
entry_reached = TRUE;
|
||||
entry_run = TRUE;
|
||||
instrument_on_fork();
|
||||
stats_on_fork();
|
||||
|
||||
@ -37,6 +40,8 @@ void entry_init(void) {
|
||||
|
||||
OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_point);
|
||||
|
||||
if (dlopen(NULL, RTLD_NOW) == NULL) { FATAL("Failed to dlopen: %d", errno); }
|
||||
|
||||
}
|
||||
|
||||
void entry_start(void) {
|
||||
@ -49,6 +54,7 @@ static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(cpu_context);
|
||||
UNUSED_PARAMETER(user_data);
|
||||
entry_compiled = TRUE;
|
||||
entry_launch();
|
||||
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
* 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));
|
||||
excluded = range_is_excluded(GUM_ADDRESS(instr->address));
|
||||
|
||||
stats_collect(instr, begin);
|
||||
|
||||
@ -173,11 +173,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
instrument_debug_start(instr->address, output);
|
||||
instrument_coverage_start(instr->address);
|
||||
|
||||
if (likely(entry_reached)) {
|
||||
|
||||
prefetch_write(GSIZE_TO_POINTER(instr->address));
|
||||
|
||||
}
|
||||
prefetch_write(GSIZE_TO_POINTER(instr->address));
|
||||
|
||||
if (likely(!excluded)) {
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
@ -277,8 +278,6 @@ static void instrument_coverage_run() {
|
||||
|
||||
if (bytes != 0) { FATAL("Coverage data truncated"); }
|
||||
|
||||
if (errno != ENOENT) { FATAL("Coverage I/O error"); }
|
||||
|
||||
OKF("Coverage - Preparing");
|
||||
|
||||
coverage_get_ranges();
|
||||
@ -325,7 +324,7 @@ void instrument_coverage_init(void) {
|
||||
|
||||
g_free(path);
|
||||
|
||||
if (pipe2(coverage_pipes, O_DIRECT) != 0) { FATAL("Failed to create pipes"); }
|
||||
if (pipe(coverage_pipes) != 0) { FATAL("Failed to create pipes"); }
|
||||
|
||||
coverage_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
if (coverage_hash == NULL) {
|
||||
|
@ -171,6 +171,12 @@ class Afl {
|
||||
static setPersistentReturn(address) {
|
||||
Afl.jsApiSetPersistentReturn(address);
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`.
|
||||
*/
|
||||
static setPrefetchBackpatchDisable() {
|
||||
Afl.jsApiSetPrefetchBackpatchDisable();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_PREFETCH`.
|
||||
*/
|
||||
@ -184,6 +190,12 @@ class Afl {
|
||||
static setStalkerCallback(callback) {
|
||||
Afl.jsApiSetStalkerCallback(callback);
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_STALKER_IC_ENTRIES`.
|
||||
*/
|
||||
static setStalkerIcEntries(val) {
|
||||
Afl.jsApiSetStalkerIcEntries(val);
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as
|
||||
* an argument.
|
||||
@ -199,12 +211,6 @@ class Afl {
|
||||
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.
|
||||
@ -254,11 +260,12 @@ Afl.jsApiSetPersistentCount = Afl.jsApiGetFunction("js_api_set_persistent_count"
|
||||
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.jsApiSetPrefetchBackpatchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_backpatch_disable", "void", []);
|
||||
Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []);
|
||||
Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]);
|
||||
Afl.jsApiSetStalkerIcEntries = Afl.jsApiGetFunction("js_api_set_stalker_ic_entries", "void", ["uint32"]);
|
||||
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(
|
||||
|
@ -7,8 +7,10 @@
|
||||
#include "persistent.h"
|
||||
#include "prefetch.h"
|
||||
#include "ranges.h"
|
||||
#include "stalker.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_done() {
|
||||
|
||||
js_done = TRUE;
|
||||
@ -127,6 +129,13 @@ __attribute__((visibility("default"))) void js_api_set_prefetch_disable(void) {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void
|
||||
js_api_set_prefetch_backpatch_disable(void) {
|
||||
|
||||
prefetch_backpatch = FALSE;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
|
||||
void) {
|
||||
|
||||
@ -180,12 +189,6 @@ __attribute__((visibility("default"))) void js_api_set_stats_interval(
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_stats_transitions() {
|
||||
|
||||
stats_transitions = TRUE;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_persistent_hook(
|
||||
void *address) {
|
||||
|
||||
@ -206,3 +209,10 @@ __attribute__((visibility("default"))) void js_api_set_stalker_callback(
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_stalker_ic_entries(
|
||||
guint val) {
|
||||
|
||||
stalker_ic_entries = val;
|
||||
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ void persistent_init(void) {
|
||||
void persistent_prologue(GumStalkerOutput *output) {
|
||||
|
||||
OKF("AFL_FRIDA_PERSISTENT_ADDR reached");
|
||||
entry_reached = TRUE;
|
||||
entry_compiled = TRUE;
|
||||
ranges_exclude();
|
||||
stalker_trust();
|
||||
persistent_prologue_arch(output);
|
||||
|
@ -6,32 +6,66 @@
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "entry.h"
|
||||
#include "intercept.h"
|
||||
#include "prefetch.h"
|
||||
#include "stalker.h"
|
||||
#include "util.h"
|
||||
|
||||
#define TRUST 0
|
||||
#define PREFETCH_SIZE 65536
|
||||
#define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *))
|
||||
|
||||
#define BP_SIZE 524288
|
||||
|
||||
typedef struct {
|
||||
|
||||
size_t count;
|
||||
void * entry[PREFETCH_ENTRIES];
|
||||
|
||||
guint8 backpatch_data[BP_SIZE];
|
||||
gsize backpatch_size;
|
||||
|
||||
} prefetch_data_t;
|
||||
|
||||
gboolean prefetch_enable = TRUE;
|
||||
gboolean prefetch_backpatch = TRUE;
|
||||
|
||||
static prefetch_data_t *prefetch_data = NULL;
|
||||
static int prefetch_shm_id = -1;
|
||||
|
||||
static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
|
||||
const GumBackpatch *backpatch,
|
||||
gsize size) {
|
||||
|
||||
UNUSED_PARAMETER(self);
|
||||
if (!entry_run) { return; }
|
||||
gsize remaining =
|
||||
sizeof(prefetch_data->backpatch_data) - prefetch_data->backpatch_size;
|
||||
if (sizeof(gsize) + size > remaining) { return; }
|
||||
|
||||
*(gsize *)(&prefetch_data->backpatch_data[prefetch_data->backpatch_size]) =
|
||||
size;
|
||||
prefetch_data->backpatch_size += sizeof(gsize);
|
||||
|
||||
memcpy(&prefetch_data->backpatch_data[prefetch_data->backpatch_size],
|
||||
backpatch, size);
|
||||
prefetch_data->backpatch_size += size;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* We do this from the transformer since we need one anyway for coverage, this
|
||||
* saves the need to use an event sink.
|
||||
*/
|
||||
void prefetch_write(void *addr) {
|
||||
|
||||
#if defined(__aarch64__)
|
||||
if (!entry_compiled) { return; }
|
||||
#else
|
||||
if (!entry_run) { return; }
|
||||
#endif
|
||||
|
||||
/* Bail if we aren't initialized */
|
||||
if (prefetch_data == NULL) return;
|
||||
|
||||
@ -51,10 +85,7 @@ void prefetch_write(void *addr) {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the IPC region one block at the time and prefetch it
|
||||
*/
|
||||
void prefetch_read(void) {
|
||||
static void prefetch_read_blocks(void) {
|
||||
|
||||
GumStalker *stalker = stalker_get();
|
||||
if (prefetch_data == NULL) return;
|
||||
@ -74,10 +105,60 @@ void prefetch_read(void) {
|
||||
|
||||
}
|
||||
|
||||
static void prefetch_read_patches(void) {
|
||||
|
||||
gsize offset = 0;
|
||||
GumStalker * stalker = stalker_get();
|
||||
GumBackpatch *backpatch = NULL;
|
||||
|
||||
for (gsize remaining = prefetch_data->backpatch_size - offset;
|
||||
remaining > sizeof(gsize);
|
||||
remaining = prefetch_data->backpatch_size - offset) {
|
||||
|
||||
gsize size = *(gsize *)(&prefetch_data->backpatch_data[offset]);
|
||||
offset += sizeof(gsize);
|
||||
|
||||
if (prefetch_data->backpatch_size - offset < size) {
|
||||
|
||||
FATAL("Incomplete backpatch entry");
|
||||
|
||||
}
|
||||
|
||||
backpatch = (GumBackpatch *)&prefetch_data->backpatch_data[offset];
|
||||
gum_stalker_prefetch_backpatch(stalker, backpatch);
|
||||
offset += size;
|
||||
|
||||
}
|
||||
|
||||
prefetch_data->backpatch_size = 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the IPC region one block at the time and prefetch it
|
||||
*/
|
||||
void prefetch_read(void) {
|
||||
|
||||
prefetch_read_blocks();
|
||||
prefetch_read_patches();
|
||||
|
||||
}
|
||||
|
||||
void prefetch_config(void) {
|
||||
|
||||
prefetch_enable = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL);
|
||||
|
||||
if (prefetch_enable) {
|
||||
|
||||
prefetch_backpatch =
|
||||
(getenv("AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH") == NULL);
|
||||
|
||||
} else {
|
||||
|
||||
prefetch_backpatch = FALSE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int prefetch_on_fork(void) {
|
||||
@ -97,8 +178,9 @@ static void prefetch_hook_fork(void) {
|
||||
|
||||
void prefetch_init(void) {
|
||||
|
||||
g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE);
|
||||
OKF("Instrumentation - prefetch [%c]", prefetch_enable ? 'X' : ' ');
|
||||
OKF("Instrumentation - prefetch_backpatch [%c]",
|
||||
prefetch_backpatch ? 'X' : ' ');
|
||||
|
||||
if (!prefetch_enable) { return; }
|
||||
/*
|
||||
@ -131,5 +213,11 @@ void prefetch_init(void) {
|
||||
|
||||
prefetch_hook_fork();
|
||||
|
||||
if (!prefetch_backpatch) { return; }
|
||||
|
||||
GumStalkerObserver * observer = stalker_get_observer();
|
||||
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
|
||||
iface->notify_backpatch = gum_afl_stalker_backpatcher_notify;
|
||||
|
||||
}
|
||||
|
||||
|
@ -635,9 +635,7 @@ void ranges_init(void) {
|
||||
|
||||
}
|
||||
|
||||
gboolean range_is_excluded(gpointer address) {
|
||||
|
||||
GumAddress test = GUM_ADDRESS(address);
|
||||
gboolean range_is_excluded(GumAddress address) {
|
||||
|
||||
if (ranges == NULL) { return false; }
|
||||
|
||||
@ -646,9 +644,9 @@ gboolean range_is_excluded(gpointer address) {
|
||||
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
|
||||
GumAddress curr_limit = curr->base_address + curr->size;
|
||||
|
||||
if (test < curr->base_address) { return false; }
|
||||
if (address < curr->base_address) { return false; }
|
||||
|
||||
if (test < curr_limit) { return true; }
|
||||
if (address < curr_limit) { return true; }
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,67 @@
|
||||
#include "debug.h"
|
||||
|
||||
#include "instrument.h"
|
||||
#include "prefetch.h"
|
||||
#include "stalker.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
guint stalker_ic_entries = 0;
|
||||
|
||||
static GumStalker *stalker = NULL;
|
||||
|
||||
struct _GumAflStalkerObserver {
|
||||
|
||||
GObject parent;
|
||||
|
||||
};
|
||||
|
||||
#define GUM_TYPE_AFL_STALKER_OBSERVER (gum_afl_stalker_observer_get_type())
|
||||
G_DECLARE_FINAL_TYPE(GumAflStalkerObserver, gum_afl_stalker_observer, GUM,
|
||||
AFL_STALKER_OBSERVER, GObject)
|
||||
|
||||
static void gum_afl_stalker_observer_iface_init(gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
static void gum_afl_stalker_observer_class_init(
|
||||
GumAflStalkerObserverClass *klass);
|
||||
static void gum_afl_stalker_observer_init(GumAflStalkerObserver *self);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED(
|
||||
GumAflStalkerObserver, gum_afl_stalker_observer, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE(GUM_TYPE_STALKER_OBSERVER,
|
||||
gum_afl_stalker_observer_iface_init))
|
||||
|
||||
static GumAflStalkerObserver *observer = NULL;
|
||||
|
||||
static void gum_afl_stalker_observer_iface_init(gpointer g_iface,
|
||||
gpointer iface_data) {
|
||||
|
||||
UNUSED_PARAMETER(g_iface);
|
||||
UNUSED_PARAMETER(iface_data);
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_observer_class_init(
|
||||
GumAflStalkerObserverClass *klass) {
|
||||
|
||||
UNUSED_PARAMETER(klass);
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_observer_init(GumAflStalkerObserver *self) {
|
||||
|
||||
UNUSED_PARAMETER(self);
|
||||
|
||||
}
|
||||
|
||||
void stalker_config(void) {
|
||||
|
||||
if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); }
|
||||
|
||||
stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES");
|
||||
|
||||
observer = g_object_new(GUM_TYPE_AFL_STALKER_OBSERVER, NULL);
|
||||
|
||||
}
|
||||
|
||||
static gboolean stalker_exclude_self(const GumRangeDetails *details,
|
||||
@ -35,7 +87,26 @@ static gboolean stalker_exclude_self(const GumRangeDetails *details,
|
||||
|
||||
void stalker_init(void) {
|
||||
|
||||
OKF("Stalker - ic_entries [%u]", stalker_ic_entries);
|
||||
|
||||
#if !(defined(__x86_64__) || defined(__i386__))
|
||||
if (stalker_ic_entries != 0) {
|
||||
|
||||
FATAL("AFL_FRIDA_STALKER_IC_ENTRIES not supported");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (stalker_ic_entries == 0) { stalker_ic_entries = 32; }
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
stalker =
|
||||
g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries, NULL);
|
||||
#else
|
||||
stalker = gum_stalker_new();
|
||||
#endif
|
||||
|
||||
if (stalker == NULL) { FATAL("Failed to initialize stalker"); }
|
||||
|
||||
gum_stalker_set_trust_threshold(stalker, -1);
|
||||
@ -57,6 +128,8 @@ void stalker_start(void) {
|
||||
GumStalkerTransformer *transformer = instrument_get_transformer();
|
||||
gum_stalker_follow_me(stalker, transformer, NULL);
|
||||
|
||||
gum_stalker_set_observer(stalker, GUM_STALKER_OBSERVER(observer));
|
||||
|
||||
}
|
||||
|
||||
void stalker_trust(void) {
|
||||
@ -65,3 +138,10 @@ void stalker_trust(void) {
|
||||
|
||||
}
|
||||
|
||||
GumStalkerObserver *stalker_get_observer(void) {
|
||||
|
||||
if (observer == NULL) { FATAL("Stalker not yet initialized"); }
|
||||
return GUM_STALKER_OBSERVER(observer);
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,35 +11,325 @@
|
||||
#include "debug.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "entry.h"
|
||||
#include "stalker.h"
|
||||
#include "stats.h"
|
||||
|
||||
#define MICRO_TO_SEC 1000000
|
||||
|
||||
stats_data_header_t *stats_data = NULL;
|
||||
char * stats_filename = NULL;
|
||||
guint64 stats_interval = 0;
|
||||
static guint64 stats_interval_us = 0;
|
||||
static int stats_fd = -1;
|
||||
static stats_data_t *stats_data = MAP_FAILED;
|
||||
|
||||
static int stats_parent_pid = -1;
|
||||
static int stats_fd = -1;
|
||||
void stats_write(void) {
|
||||
|
||||
char * stats_filename = NULL;
|
||||
guint64 stats_interval = 0;
|
||||
gboolean stats_transitions = FALSE;
|
||||
if (stats_filename == NULL) { return; }
|
||||
|
||||
if (stats_interval == 0) { return; }
|
||||
|
||||
guint64 current_time = g_get_monotonic_time();
|
||||
if ((current_time - stats_data->prev.stats_time) < stats_interval_us) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
IGNORED_RETURN(ftruncate(stats_fd, 0));
|
||||
IGNORED_RETURN(lseek(stats_fd, 0, SEEK_SET));
|
||||
|
||||
stats_data->curr.stats_time = current_time;
|
||||
|
||||
GDateTime *date_time = g_date_time_new_now_local();
|
||||
char * date_string = g_date_time_format(date_time, "%Y-%m-%d");
|
||||
char * time_string = g_date_time_format(date_time, "%H:%M:%S");
|
||||
guint elapsed = (stats_data->curr.stats_time - stats_data->prev.stats_time) /
|
||||
MICRO_TO_SEC;
|
||||
|
||||
stats_print("stats\n");
|
||||
stats_print("-----\n");
|
||||
|
||||
stats_print("%-21s %s %s\n", "Time", date_string, time_string);
|
||||
stats_print("%-30s %10u seconds \n", "Elapsed", elapsed);
|
||||
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
g_free(time_string);
|
||||
g_free(date_string);
|
||||
g_date_time_unref(date_time);
|
||||
|
||||
stats_write_arch(stats_data);
|
||||
|
||||
memcpy(&stats_data->prev, &stats_data->curr, sizeof(stats_t));
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_total(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.total++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_call_imm(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.call_imm++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_call_reg(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.call_reg++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_call_mem(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.call_mem++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_excluded_call_reg(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.excluded_call_reg++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_ret_slow_path(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.ret_slow_path++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_ret(GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.ret++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_post_call_invoke(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.post_call_invoke++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_excluded_call_imm(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.excluded_call_imm++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_imm(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_imm++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_reg(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_reg++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_mem(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_mem++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_imm(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_imm++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_mem(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_mem++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_reg(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_reg++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_jcxz(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_jcxz++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_cc(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_cc++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_cbz(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_cbz++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_cbnz(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_cbnz++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_tbz(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_tbz++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_cond_tbnz(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_cond_tbnz++;
|
||||
|
||||
}
|
||||
|
||||
static void gum_afl_stalker_stats_increment_jmp_continuation(
|
||||
GumStalkerObserver *observer) {
|
||||
|
||||
UNUSED_PARAMETER(observer);
|
||||
|
||||
if (!entry_compiled) { return; }
|
||||
stats_data->curr.jmp_continuation++;
|
||||
|
||||
}
|
||||
|
||||
static void stats_observer_init(GumStalkerObserver *observer) {
|
||||
|
||||
GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer);
|
||||
iface->increment_total = gum_afl_stalker_stats_increment_total;
|
||||
iface->increment_call_imm = gum_afl_stalker_stats_increment_call_imm;
|
||||
iface->increment_call_reg = gum_afl_stalker_stats_increment_call_reg;
|
||||
iface->increment_call_mem = gum_afl_stalker_stats_increment_call_mem;
|
||||
iface->increment_excluded_call_reg =
|
||||
gum_afl_stalker_stats_increment_excluded_call_reg;
|
||||
iface->increment_ret_slow_path =
|
||||
gum_afl_stalker_stats_increment_ret_slow_path;
|
||||
iface->increment_ret = gum_afl_stalker_stats_increment_ret;
|
||||
iface->increment_post_call_invoke =
|
||||
gum_afl_stalker_stats_increment_post_call_invoke;
|
||||
iface->increment_excluded_call_imm =
|
||||
gum_afl_stalker_stats_increment_excluded_call_imm;
|
||||
iface->increment_jmp_imm = gum_afl_stalker_stats_increment_jmp_imm;
|
||||
iface->increment_jmp_reg = gum_afl_stalker_stats_increment_jmp_reg;
|
||||
iface->increment_jmp_mem = gum_afl_stalker_stats_increment_jmp_mem;
|
||||
iface->increment_jmp_cond_imm = gum_afl_stalker_stats_increment_jmp_cond_imm;
|
||||
iface->increment_jmp_cond_mem = gum_afl_stalker_stats_increment_jmp_cond_mem;
|
||||
iface->increment_jmp_cond_reg = gum_afl_stalker_stats_increment_jmp_cond_reg;
|
||||
iface->increment_jmp_cond_jcxz =
|
||||
gum_afl_stalker_stats_increment_jmp_cond_jcxz;
|
||||
iface->increment_jmp_cond_cc = gum_afl_stalker_stats_increment_jmp_cond_cc;
|
||||
iface->increment_jmp_cond_cbz = gum_afl_stalker_stats_increment_jmp_cond_cbz;
|
||||
iface->increment_jmp_cond_cbnz =
|
||||
gum_afl_stalker_stats_increment_jmp_cond_cbnz;
|
||||
iface->increment_jmp_cond_tbz = gum_afl_stalker_stats_increment_jmp_cond_tbz;
|
||||
iface->increment_jmp_cond_tbnz =
|
||||
gum_afl_stalker_stats_increment_jmp_cond_tbnz;
|
||||
iface->increment_jmp_continuation =
|
||||
gum_afl_stalker_stats_increment_jmp_continuation;
|
||||
|
||||
}
|
||||
|
||||
void stats_config(void) {
|
||||
|
||||
stats_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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void stats_init(void) {
|
||||
|
||||
stats_parent_pid = getpid();
|
||||
|
||||
OKF("Stats - file [%s]", stats_filename);
|
||||
OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval);
|
||||
|
||||
@ -52,22 +342,11 @@ void stats_init(void) {
|
||||
}
|
||||
|
||||
if (stats_interval == 0) { stats_interval = 10; }
|
||||
stats_interval_us = stats_interval * MICRO_TO_SEC;
|
||||
|
||||
if (stats_filename == NULL) { return; }
|
||||
|
||||
if (!stats_is_supported_arch()) {
|
||||
|
||||
FATAL("Stats is not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
char *path = NULL;
|
||||
|
||||
if (stats_filename == NULL) { return; }
|
||||
|
||||
if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); }
|
||||
|
||||
path = g_canonicalize_filename(stats_filename, g_get_current_dir());
|
||||
char *path = g_canonicalize_filename(stats_filename, g_get_current_dir());
|
||||
|
||||
OKF("Stats - path [%s]", path);
|
||||
|
||||
@ -78,14 +357,16 @@ void stats_init(void) {
|
||||
|
||||
g_free(path);
|
||||
|
||||
size_t data_size = stats_data_size_arch();
|
||||
|
||||
int shm_id = shmget(IPC_PRIVATE, data_size, IPC_CREAT | IPC_EXCL | 0600);
|
||||
int shm_id =
|
||||
shmget(IPC_PRIVATE, sizeof(stats_data_t), 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);
|
||||
|
||||
GumStalkerObserver *observer = stalker_get_observer();
|
||||
stats_observer_init(observer);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
@ -96,119 +377,39 @@ void stats_init(void) {
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(stats_data, '\0', data_size);
|
||||
memset(stats_data, '\0', sizeof(stats_data_t));
|
||||
|
||||
}
|
||||
|
||||
void stats_vprint(int fd, char *format, va_list ap) {
|
||||
|
||||
char buffer[4096] = {0};
|
||||
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);
|
||||
starts_arch_init();
|
||||
|
||||
}
|
||||
|
||||
void stats_print(char *format, ...) {
|
||||
|
||||
char buffer[4096] = {0};
|
||||
int len;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
stats_vprint(stats_fd, format, ap);
|
||||
|
||||
if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; }
|
||||
|
||||
len = strnlen(buffer, sizeof(buffer));
|
||||
IGNORED_RETURN(write(stats_fd, buffer, len));
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void stats_on_fork(void) {
|
||||
|
||||
guint64 current_time;
|
||||
|
||||
if (stats_filename == NULL) { return; }
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
stats_write();
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
if (!entry_compiled) { return; }
|
||||
if (stats_filename == NULL) { return; }
|
||||
stats_collect_arch(instr, begin);
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,27 +7,22 @@
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
gboolean stats_is_supported_arch(void) {
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
size_t stats_data_size_arch(void) {
|
||||
void starts_arch_init(void) {
|
||||
|
||||
FATAL("Stats not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
void stats_write_arch(void) {
|
||||
void stats_write_arch(stats_data_t *data) {
|
||||
|
||||
FATAL("Stats not supported on this architecture");
|
||||
|
||||
}
|
||||
|
||||
void stats_collect_arch(const cs_insn *instr) {
|
||||
void stats_collect_arch(const cs_insn *instr, gboolean begin) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
UNUSED_PARAMETER(begin);
|
||||
FATAL("Stats not supported on this architecture");
|
||||
|
||||
}
|
||||
|
@ -1,34 +1,323 @@
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "ranges.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MICRO_TO_SEC 1000000
|
||||
|
||||
#if defined(__aarch64__)
|
||||
|
||||
gboolean stats_is_supported_arch(void) {
|
||||
typedef struct {
|
||||
|
||||
return FALSE;
|
||||
guint64 num_blocks;
|
||||
guint64 num_instructions;
|
||||
|
||||
guint64 num_eob;
|
||||
guint64 num_reloc;
|
||||
|
||||
guint64 num_adr;
|
||||
guint64 num_adrp;
|
||||
|
||||
guint64 num_b;
|
||||
guint64 num_bcc;
|
||||
guint64 num_bl;
|
||||
guint64 num_br;
|
||||
|
||||
guint64 num_cbz;
|
||||
guint64 num_cbnz;
|
||||
|
||||
guint64 num_ldr;
|
||||
guint64 num_ldrsw;
|
||||
|
||||
guint64 num_ret;
|
||||
|
||||
guint64 num_tbz;
|
||||
guint64 num_tbnz;
|
||||
|
||||
} stats_data_arch_t;
|
||||
|
||||
static stats_data_arch_t *stats_data_arch = NULL;
|
||||
|
||||
void starts_arch_init(void) {
|
||||
|
||||
int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t),
|
||||
IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
stats_data_arch = shmat(shm_id, NULL, 0);
|
||||
g_assert(stats_data_arch != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(stats_data_arch, '\0', sizeof(stats_data_arch_t));
|
||||
|
||||
}
|
||||
|
||||
size_t stats_data_size_arch(void) {
|
||||
static void stats_write_arch_stat(char *label, guint64 value, guint64 total) {
|
||||
|
||||
FATAL("Stats not supported on this architecture");
|
||||
stats_print("%-30s ", label);
|
||||
stats_print("%10" G_GINT64_MODIFIER "u ", value);
|
||||
if (total == 0) {
|
||||
|
||||
stats_print("(--.--%%), ");
|
||||
|
||||
} else {
|
||||
|
||||
stats_print("(%5.2f%%) ", ((float)value * 100) / total);
|
||||
|
||||
}
|
||||
|
||||
stats_print("\n");
|
||||
|
||||
}
|
||||
|
||||
void stats_write_arch(void) {
|
||||
static void stats_write_arch_stat_delta(char *label, guint64 prev_value,
|
||||
guint64 curr_value, guint elapsed,
|
||||
guint64 prev_total,
|
||||
guint64 curr_total) {
|
||||
|
||||
FATAL("Stats not supported on this architecture");
|
||||
guint64 delta = curr_value - prev_value;
|
||||
guint64 delta_total = curr_total - prev_total;
|
||||
guint64 per_sec = delta / elapsed;
|
||||
|
||||
stats_print("%-30s ", label);
|
||||
|
||||
stats_print("%10" G_GINT64_MODIFIER "u ", curr_value);
|
||||
if (curr_total == 0) {
|
||||
|
||||
stats_print("(--.--%%), ");
|
||||
|
||||
} else {
|
||||
|
||||
stats_print("(%5.2f%%) ", ((float)curr_value * 100) / curr_total);
|
||||
|
||||
}
|
||||
|
||||
stats_print("%10" G_GINT64_MODIFIER "u ", delta);
|
||||
if (delta_total == 0) {
|
||||
|
||||
stats_print("(--.--%%), ");
|
||||
|
||||
} else {
|
||||
|
||||
stats_print("(%5.2f%%) ", ((float)delta * 100) / delta_total);
|
||||
|
||||
}
|
||||
|
||||
stats_print("[%10" G_GINT64_MODIFIER "u/s]", per_sec);
|
||||
stats_print("\n");
|
||||
|
||||
}
|
||||
|
||||
void stats_collect_arch(const cs_insn *instr) {
|
||||
void stats_write_arch(stats_data_t *data) {
|
||||
|
||||
UNUSED_PARAMETER(instr);
|
||||
FATAL("Stats not supported on this architecture");
|
||||
guint elapsed =
|
||||
(data->curr.stats_time - data->prev.stats_time) / MICRO_TO_SEC;
|
||||
stats_print("%-30s %10s %19s\n", "Transitions", "cumulative", "delta");
|
||||
stats_print("%-30s %10s %19s\n", "-----------", "----------", "-----");
|
||||
stats_print(
|
||||
"%-30s %10" G_GINT64_MODIFIER "u %-8s %10" G_GINT64_MODIFIER "u\n",
|
||||
"total", data->curr.total, "", data->curr.total - data->prev.total);
|
||||
stats_write_arch_stat_delta("call_imm", data->prev.call_imm,
|
||||
data->curr.call_imm, elapsed, data->prev.total,
|
||||
data->curr.total);
|
||||
stats_write_arch_stat_delta("call_reg", data->prev.call_reg,
|
||||
data->curr.call_reg, elapsed, data->prev.total,
|
||||
data->curr.total);
|
||||
stats_write_arch_stat_delta("excluded_call_reg", data->prev.excluded_call_reg,
|
||||
data->curr.excluded_call_reg, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("ret", data->prev.ret, data->curr.ret, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("post_call_invoke", data->prev.post_call_invoke,
|
||||
data->curr.post_call_invoke, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("excluded_call_imm", data->prev.excluded_call_imm,
|
||||
data->curr.excluded_call_imm, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_imm", data->prev.jmp_imm, data->curr.jmp_imm,
|
||||
elapsed, data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_reg", data->prev.jmp_reg, data->curr.jmp_reg,
|
||||
elapsed, data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_cc", data->prev.jmp_cond_cc,
|
||||
data->curr.jmp_cond_cc, elapsed, data->prev.total,
|
||||
data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_cbz", data->prev.jmp_cond_cbz,
|
||||
data->curr.jmp_cond_cbz, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_cbnz", data->prev.jmp_cond_cbnz,
|
||||
data->curr.jmp_cond_cbnz, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_tbz", data->prev.jmp_cond_tbz,
|
||||
data->curr.jmp_cond_tbz, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_tbnz", data->prev.jmp_cond_tbnz,
|
||||
data->curr.jmp_cond_tbnz, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_continuation", data->prev.jmp_continuation,
|
||||
data->curr.jmp_continuation, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
stats_print("Instrumentation\n");
|
||||
stats_print("---------------\n");
|
||||
stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Instructions",
|
||||
stats_data_arch->num_instructions);
|
||||
stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Blocks",
|
||||
stats_data_arch->num_blocks);
|
||||
|
||||
if (stats_data_arch->num_blocks != 0) {
|
||||
|
||||
stats_print(
|
||||
"%-30s %10" G_GINT64_MODIFIER "u\n", "Avg Instructions / Block ",
|
||||
stats_data_arch->num_instructions / stats_data_arch->num_blocks);
|
||||
|
||||
}
|
||||
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
guint64 num_instructions = stats_data_arch->num_instructions;
|
||||
|
||||
stats_print("EOB Instructions\n");
|
||||
stats_print("----------------\n");
|
||||
stats_write_arch_stat("Total", stats_data_arch->num_eob, num_instructions);
|
||||
stats_write_arch_stat("B", stats_data_arch->num_b, num_instructions);
|
||||
stats_write_arch_stat("Bcc", stats_data_arch->num_bcc, num_instructions);
|
||||
stats_write_arch_stat("BL", stats_data_arch->num_bl, num_instructions);
|
||||
stats_write_arch_stat("BR", stats_data_arch->num_br, num_instructions);
|
||||
stats_write_arch_stat("CBZ", stats_data_arch->num_cbz, num_instructions);
|
||||
stats_write_arch_stat("CBNZ", stats_data_arch->num_cbnz, num_instructions);
|
||||
stats_write_arch_stat("RET", stats_data_arch->num_ret, num_instructions);
|
||||
stats_write_arch_stat("TBZ", stats_data_arch->num_tbz, num_instructions);
|
||||
stats_write_arch_stat("TBNZ", stats_data_arch->num_tbnz, num_instructions);
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
stats_print("Relocated Instructions\n");
|
||||
stats_print("----------------------\n");
|
||||
stats_write_arch_stat("Total", stats_data_arch->num_reloc, num_instructions);
|
||||
|
||||
stats_write_arch_stat("ADR", stats_data_arch->num_adr, num_instructions);
|
||||
stats_write_arch_stat("ADRP", stats_data_arch->num_adrp, num_instructions);
|
||||
stats_write_arch_stat("LDR", stats_data_arch->num_ldr, num_instructions);
|
||||
stats_write_arch_stat("LDRSW", stats_data_arch->num_ldrsw, num_instructions);
|
||||
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
}
|
||||
|
||||
void stats_collect_arch(const cs_insn *instr, gboolean begin) {
|
||||
|
||||
if (stats_data_arch == NULL) { return; }
|
||||
if (begin) { stats_data_arch->num_blocks++; }
|
||||
stats_data_arch->num_instructions++;
|
||||
|
||||
switch (instr->id) {
|
||||
|
||||
case ARM64_INS_ADR:
|
||||
stats_data_arch->num_adr++;
|
||||
stats_data_arch->num_reloc++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_ADRP:
|
||||
stats_data_arch->num_adrp++;
|
||||
stats_data_arch->num_reloc++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_B:
|
||||
switch (instr->detail->arm64.cc) {
|
||||
|
||||
case ARM64_CC_INVALID:
|
||||
case ARM64_CC_AL:
|
||||
case ARM64_CC_NV:
|
||||
stats_data_arch->num_b++;
|
||||
break;
|
||||
default:
|
||||
stats_data_arch->num_bcc++;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_BR:
|
||||
case ARM64_INS_BRAA:
|
||||
case ARM64_INS_BRAAZ:
|
||||
case ARM64_INS_BRAB:
|
||||
case ARM64_INS_BRABZ:
|
||||
stats_data_arch->num_br++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_BL:
|
||||
case ARM64_INS_BLR:
|
||||
case ARM64_INS_BLRAA:
|
||||
case ARM64_INS_BLRAAZ:
|
||||
case ARM64_INS_BLRAB:
|
||||
case ARM64_INS_BLRABZ:
|
||||
stats_data_arch->num_bl++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_CBZ:
|
||||
stats_data_arch->num_cbz++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_CBNZ:
|
||||
stats_data_arch->num_cbnz++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_LDR:
|
||||
stats_data_arch->num_ldr++;
|
||||
stats_data_arch->num_reloc++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_LDRSW:
|
||||
stats_data_arch->num_ldrsw++;
|
||||
stats_data_arch->num_reloc++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_RET:
|
||||
case ARM64_INS_RETAA:
|
||||
case ARM64_INS_RETAB:
|
||||
stats_data_arch->num_ret++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_TBZ:
|
||||
stats_data_arch->num_tbz++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
case ARM64_INS_TBNZ:
|
||||
stats_data_arch->num_tbnz++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,325 +0,0 @@
|
||||
#include "frida-gumjs.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;
|
||||
|
||||
guint64 num_rip_relative_type[X86_INS_ENDING];
|
||||
char name_rip_relative_type[X86_INS_ENDING][CS_MNEMONIC_SIZE];
|
||||
|
||||
} 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));
|
||||
|
||||
for (size_t i = 0; i < X86_INS_ENDING; i++) {
|
||||
|
||||
if (stats_data_arch->num_rip_relative_type[i] != 0) {
|
||||
|
||||
stats_print(" %10d %s\n",
|
||||
stats_data_arch->num_rip_relative_type[i],
|
||||
stats_data_arch->name_rip_relative_type[i]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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++;
|
||||
stats_data_arch->num_rip_relative_type[instr->id]++;
|
||||
memcpy(stats_data_arch->name_rip_relative_type[instr->id], instr->mnemonic,
|
||||
CS_MNEMONIC_SIZE);
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1,36 +0,0 @@
|
||||
#include "frida-gumjs.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
|
||||
|
420
frida_mode/src/stats/stats_x86_64.c
Normal file
420
frida_mode/src/stats/stats_x86_64.c
Normal file
@ -0,0 +1,420 @@
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gumjs.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "ranges.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MICRO_TO_SEC 1000000
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
|
||||
typedef struct {
|
||||
|
||||
guint64 num_blocks;
|
||||
guint64 num_instructions;
|
||||
|
||||
guint64 num_eob;
|
||||
|
||||
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;
|
||||
|
||||
guint64 num_rip_relative_type[X86_INS_ENDING];
|
||||
char name_rip_relative_type[X86_INS_ENDING][CS_MNEMONIC_SIZE];
|
||||
|
||||
} stats_data_arch_t;
|
||||
|
||||
static stats_data_arch_t *stats_data_arch = NULL;
|
||||
|
||||
void starts_arch_init(void) {
|
||||
|
||||
int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t),
|
||||
IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); }
|
||||
|
||||
stats_data_arch = shmat(shm_id, NULL, 0);
|
||||
g_assert(stats_data_arch != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(stats_data_arch, '\0', sizeof(stats_data_arch_t));
|
||||
|
||||
}
|
||||
|
||||
static void stats_write_arch_stat(char *label, guint64 value, guint64 total) {
|
||||
|
||||
stats_print("%-30s ", label);
|
||||
stats_print("%10" G_GINT64_MODIFIER "u ", value);
|
||||
if (total == 0) {
|
||||
|
||||
stats_print("(--.--%%), ");
|
||||
|
||||
} else {
|
||||
|
||||
stats_print("(%5.2f%%) ", ((float)value * 100) / total);
|
||||
|
||||
}
|
||||
|
||||
stats_print("\n");
|
||||
|
||||
}
|
||||
|
||||
static void stats_write_arch_stat_delta(char *label, guint64 prev_value,
|
||||
guint64 curr_value, guint elapsed,
|
||||
guint64 prev_total,
|
||||
guint64 curr_total) {
|
||||
|
||||
guint64 delta = curr_value - prev_value;
|
||||
guint64 delta_total = curr_total - prev_total;
|
||||
guint64 per_sec = delta / elapsed;
|
||||
|
||||
stats_print("%-30s ", label);
|
||||
|
||||
stats_print("%10" G_GINT64_MODIFIER "u ", curr_value);
|
||||
if (curr_total == 0) {
|
||||
|
||||
stats_print("(--.--%%), ");
|
||||
|
||||
} else {
|
||||
|
||||
stats_print("(%5.2f%%) ", ((float)curr_value * 100) / curr_total);
|
||||
|
||||
}
|
||||
|
||||
stats_print("%10" G_GINT64_MODIFIER "u ", delta);
|
||||
if (delta_total == 0) {
|
||||
|
||||
stats_print("(--.--%%), ");
|
||||
|
||||
} else {
|
||||
|
||||
stats_print("(%5.2f%%) ", ((float)delta * 100) / delta_total);
|
||||
|
||||
}
|
||||
|
||||
stats_print("[%10" G_GINT64_MODIFIER "u/s]", per_sec);
|
||||
stats_print("\n");
|
||||
|
||||
}
|
||||
|
||||
void stats_write_arch(stats_data_t *data) {
|
||||
|
||||
guint elapsed =
|
||||
(data->curr.stats_time - data->prev.stats_time) / MICRO_TO_SEC;
|
||||
stats_print("%-30s %10s %19s\n", "Transitions", "cumulative", "delta");
|
||||
stats_print("%-30s %10s %19s\n", "-----------", "----------", "-----");
|
||||
stats_print(
|
||||
"%-30s %10" G_GINT64_MODIFIER "u %-8s %10" G_GINT64_MODIFIER "u\n",
|
||||
"total", data->curr.total, "", data->curr.total - data->prev.total);
|
||||
stats_write_arch_stat_delta("call_imm", data->prev.call_imm,
|
||||
data->curr.call_imm, elapsed, data->prev.total,
|
||||
data->curr.total);
|
||||
stats_write_arch_stat_delta("call_reg", data->prev.call_reg,
|
||||
data->curr.call_reg, elapsed, data->prev.total,
|
||||
data->curr.total);
|
||||
stats_write_arch_stat_delta("call_mem", data->prev.call_mem,
|
||||
data->curr.call_mem, elapsed, data->prev.total,
|
||||
data->curr.total);
|
||||
stats_write_arch_stat_delta("ret_slow_path", data->prev.ret_slow_path,
|
||||
data->curr.ret_slow_path, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("post_call_invoke", data->prev.post_call_invoke,
|
||||
data->curr.post_call_invoke, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("excluded_call_imm", data->prev.excluded_call_imm,
|
||||
data->curr.excluded_call_imm, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_imm", data->prev.jmp_imm, data->curr.jmp_imm,
|
||||
elapsed, data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_reg", data->prev.jmp_reg, data->curr.jmp_reg,
|
||||
elapsed, data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_mem", data->prev.jmp_mem, data->curr.jmp_mem,
|
||||
elapsed, data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_imm", data->prev.jmp_cond_imm,
|
||||
data->curr.jmp_cond_imm, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_mem", data->prev.jmp_cond_mem,
|
||||
data->curr.jmp_cond_mem, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_reg", data->prev.jmp_cond_reg,
|
||||
data->curr.jmp_cond_reg, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_cond_jcxz", data->prev.jmp_cond_jcxz,
|
||||
data->curr.jmp_cond_jcxz, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_write_arch_stat_delta("jmp_continuation", data->prev.jmp_continuation,
|
||||
data->curr.jmp_continuation, elapsed,
|
||||
data->prev.total, data->curr.total);
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
stats_print("Instrumentation\n");
|
||||
stats_print("---------------\n");
|
||||
stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Instructions",
|
||||
stats_data_arch->num_instructions);
|
||||
stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Blocks",
|
||||
stats_data_arch->num_blocks);
|
||||
|
||||
if (stats_data_arch->num_blocks != 0) {
|
||||
|
||||
stats_print(
|
||||
"%-30s %10" G_GINT64_MODIFIER "u\n", "Avg Instructions / Block ",
|
||||
stats_data_arch->num_instructions / stats_data_arch->num_blocks);
|
||||
|
||||
}
|
||||
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
guint64 num_instructions = stats_data_arch->num_instructions;
|
||||
|
||||
stats_print("EOB Instructions\n");
|
||||
stats_print("----------------\n");
|
||||
stats_write_arch_stat("Total", stats_data_arch->num_eob, num_instructions);
|
||||
stats_write_arch_stat("Call Immediates", stats_data_arch->num_call_imm,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Call Immediates Excluded",
|
||||
stats_data_arch->num_call_imm_excluded,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Call Register", stats_data_arch->num_call_reg,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Call Memory", stats_data_arch->num_call_mem,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Jump Immediates", stats_data_arch->num_jmp_imm,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Jump Register", stats_data_arch->num_jmp_reg,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Jump Memory", stats_data_arch->num_jmp_mem,
|
||||
num_instructions);
|
||||
stats_write_arch_stat("Conditional Jump Immediates",
|
||||
stats_data_arch->num_jmp_cond_imm, num_instructions);
|
||||
stats_write_arch_stat("Conditional Jump CX Immediate",
|
||||
stats_data_arch->num_jmp_cond_jcxz, num_instructions);
|
||||
stats_write_arch_stat("Conditional Jump Register",
|
||||
stats_data_arch->num_jmp_cond_reg, num_instructions);
|
||||
stats_write_arch_stat("Conditional Jump Memory",
|
||||
stats_data_arch->num_jmp_cond_mem, num_instructions);
|
||||
stats_write_arch_stat("Returns", stats_data_arch->num_ret, num_instructions);
|
||||
stats_print("\n");
|
||||
stats_print("\n");
|
||||
|
||||
stats_print("Relocated Instructions\n");
|
||||
stats_print("----------------------\n");
|
||||
stats_write_arch_stat("Total", stats_data_arch->num_rip_relative,
|
||||
num_instructions);
|
||||
|
||||
for (size_t i = 0; i < X86_INS_ENDING; i++) {
|
||||
|
||||
if (stats_data_arch->num_rip_relative_type[i] != 0) {
|
||||
|
||||
stats_write_arch_stat(stats_data_arch->name_rip_relative_type[i],
|
||||
stats_data_arch->num_rip_relative_type[i],
|
||||
stats_data_arch->num_rip_relative);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
cs_x86 * x86 = &instr->detail->x86;
|
||||
cs_x86_op *operand = &x86->operands[0];
|
||||
|
||||
if (range_is_excluded(GUM_ADDRESS(operand->imm))) {
|
||||
|
||||
stats_data_arch->num_call_imm_excluded++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void stats_collect_call_arch(const cs_insn *instr) {
|
||||
|
||||
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) {
|
||||
|
||||
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) {
|
||||
|
||||
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) {
|
||||
|
||||
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++;
|
||||
stats_data_arch->num_rip_relative_type[instr->id]++;
|
||||
memcpy(stats_data_arch->name_rip_relative_type[instr->id], instr->mnemonic,
|
||||
CS_MNEMONIC_SIZE);
|
||||
|
||||
}
|
||||
|
||||
void stats_collect_arch(const cs_insn *instr, gboolean begin) {
|
||||
|
||||
if (stats_data_arch == NULL) { return; }
|
||||
if (begin) { stats_data_arch->num_blocks++; }
|
||||
stats_data_arch->num_instructions++;
|
||||
|
||||
switch (instr->id) {
|
||||
|
||||
case X86_INS_CALL:
|
||||
stats_collect_call_arch(instr);
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
case X86_INS_JMP:
|
||||
stats_collect_jump_arch(instr);
|
||||
stats_data_arch->num_eob++;
|
||||
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);
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
case X86_INS_JECXZ:
|
||||
case X86_INS_JRCXZ:
|
||||
stats_data_arch->num_jmp_cond_jcxz++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
case X86_INS_RET:
|
||||
stats_data_arch->num_ret++;
|
||||
stats_data_arch->num_eob++;
|
||||
break;
|
||||
default:
|
||||
stats_collect_rip_relative_arch(instr);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../../)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
TEST_CMPLOG_SRC=$(PWD)cmplog.c
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
TEST_DATA_DIR:=$(BUILD_DIR)in/
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TEST_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TEST_DATA_FILE:=$(TEST_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
|
||||
@ -142,7 +142,7 @@ $(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB)
|
||||
########## DUMMY #######
|
||||
|
||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR)
|
||||
dd if=/dev/zero bs=1M count=1 of=$@
|
||||
dd if=/dev/zero bs=1048576 count=1 of=$@
|
||||
|
||||
###### TEST DATA #######
|
||||
|
||||
|
@ -52,7 +52,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
|
||||
echo -n "$$FA$$" > $@
|
||||
|
||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
|
||||
dd if=/dev/zero bs=1M count=1 of=$@
|
||||
dd if=/dev/zero bs=1048576 count=1 of=$@
|
||||
|
||||
$(HARNESS_BIN): $(HARNESS_SRC) | $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(HARNESS_LDFLAGS) -o $@ $<
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/
|
||||
|
@ -1,9 +1,9 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../../..)/
|
||||
ROOT:=$(PWD)../../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
TEST_BIN:=$(PWD)../build/test
|
||||
TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/
|
||||
TEST_DATA_DIR:=$(PWD)../build/libpng/libpng-1.2.56/contrib/pngsuite/
|
||||
|
||||
AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in
|
||||
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
||||
@ -49,7 +49,7 @@ $(BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
|
||||
dd if=/dev/zero bs=1M count=1 of=$@
|
||||
dd if=/dev/zero bs=1048576 count=1 of=$@
|
||||
|
||||
qemu: | $(BUILD_DIR)
|
||||
AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../../../..)/
|
||||
ROOT:=$(PWD)../../../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
|
||||
@ -72,7 +72,7 @@ $(TEST_DATA_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
|
||||
dd if=/dev/zero bs=1M count=1 of=$@
|
||||
dd if=/dev/zero bs=1048576 count=1 of=$@
|
||||
|
||||
qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
|
||||
AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_QEMU_DRIVER_HOOK_OBJ) \
|
||||
@ -127,6 +127,21 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) | $(BUIL
|
||||
-- \
|
||||
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
||||
|
||||
frida_entry_slow: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
|
||||
AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \
|
||||
AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
|
||||
AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
|
||||
AFL_FRIDA_STALKER_IC_ENTRIES=2 \
|
||||
AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH=1 \
|
||||
$(ROOT)afl-fuzz \
|
||||
-D \
|
||||
-V 30 \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
||||
|
||||
frida_js_load: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
|
||||
AFL_PRELOAD=$(AFL_PRELOAD) \
|
||||
AFL_FRIDA_JS_SCRIPT=load.js \
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
|
||||
@ -124,7 +124,7 @@ $(TEST_DATA_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR)
|
||||
dd if=/dev/zero bs=1M count=1 of=$@
|
||||
dd if=/dev/zero bs=1048576 count=1 of=$@
|
||||
|
||||
###### TEST DATA #######
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
|
||||
SQLITE_BUILD_DIR:=$(BUILD_DIR)sqlite/
|
||||
@ -120,7 +120,7 @@ sqlite: $(SQLITE_TEST_DIR) $(TEST_BIN)
|
||||
########## DUMMY #######
|
||||
|
||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(SQLITE_TEST_DIR)
|
||||
dd if=/dev/zero bs=1M count=1 of=$@
|
||||
dd if=/dev/zero bs=1048576 count=1 of=$@
|
||||
|
||||
###### TEST DATA #######
|
||||
|
||||
@ -156,6 +156,22 @@ frida: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) |
|
||||
-- \
|
||||
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
||||
|
||||
frida_slow: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(SQLITE_TEST_DIR)
|
||||
AFL_FRIDA_PERSISTENT_CNT=1000000 \
|
||||
AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \
|
||||
AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
|
||||
AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
|
||||
AFL_FRIDA_STALKER_IC_ENTRIES=2 \
|
||||
AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH=1 \
|
||||
$(ROOT)afl-fuzz \
|
||||
-D \
|
||||
-V 30 \
|
||||
-O \
|
||||
-i $(SQLITE_TEST_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
||||
|
||||
debug:
|
||||
gdb \
|
||||
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
|
||||
|
@ -1,5 +1,5 @@
|
||||
PWD:=$(shell pwd)/
|
||||
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||
ROOT:=$(PWD)../../../
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
UNSTABLE_DATA_DIR:=$(BUILD_DIR)in/
|
||||
UNSTABLE_DATA_FILE:=$(UNSTABLE_DATA_DIR)in
|
||||
|
@ -202,6 +202,13 @@ class Afl {
|
||||
Afl.jsApiSetPersistentReturn(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`.
|
||||
*/
|
||||
public static setPrefetchBackpatchDisable(): void {
|
||||
Afl.jsApiSetPrefetchBackpatchDisable();
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_PREFETCH`.
|
||||
*/
|
||||
@ -217,6 +224,13 @@ class Afl {
|
||||
Afl.jsApiSetStalkerCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_STALKER_IC_ENTRIES`.
|
||||
*/
|
||||
public static setStalkerIcEntries(val: number): void {
|
||||
Afl.jsApiSetStalkerIcEntries(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as
|
||||
* an argument.
|
||||
@ -234,13 +248,6 @@ class Afl {
|
||||
Afl.jsApiSetStatsInterval(interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_STATS_TRANSITIONS`
|
||||
*/
|
||||
public static setStatsTransitions(): void {
|
||||
Afl.jsApiSetStatsTransitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
|
||||
* an argument.
|
||||
@ -356,6 +363,11 @@ class Afl {
|
||||
"void",
|
||||
["pointer"]);
|
||||
|
||||
private static readonly jsApiSetPrefetchBackpatchDisable = Afl.jsApiGetFunction(
|
||||
"js_api_set_prefetch_backpatch_disable",
|
||||
"void",
|
||||
[]);
|
||||
|
||||
private static readonly jsApiSetPrefetchDisable = Afl.jsApiGetFunction(
|
||||
"js_api_set_prefetch_disable",
|
||||
"void",
|
||||
@ -366,6 +378,11 @@ class Afl {
|
||||
"void",
|
||||
["pointer"]);
|
||||
|
||||
private static readonly jsApiSetStalkerIcEntries = Afl.jsApiGetFunction(
|
||||
"js_api_set_stalker_ic_entries",
|
||||
"void",
|
||||
["uint32"]);
|
||||
|
||||
private static readonly jsApiSetStatsFile = Afl.jsApiGetFunction(
|
||||
"js_api_set_stats_file",
|
||||
"void",
|
||||
@ -376,11 +393,6 @@ class Afl {
|
||||
"void",
|
||||
["uint64"]);
|
||||
|
||||
private static readonly jsApiSetStatsTransitions = Afl.jsApiGetFunction(
|
||||
"js_api_set_stats_transitions",
|
||||
"void",
|
||||
[]);
|
||||
|
||||
private static readonly jsApiSetStdErr = Afl.jsApiGetFunction(
|
||||
"js_api_set_stderr",
|
||||
"void",
|
||||
|
@ -60,6 +60,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_FRIDA_INST_JIT",
|
||||
"AFL_FRIDA_INST_NO_OPTIMIZE",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
|
||||
"AFL_FRIDA_INST_RANGES",
|
||||
"AFL_FRIDA_INST_SEED",
|
||||
"AFL_FRIDA_INST_TRACE",
|
||||
@ -74,7 +75,6 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_FRIDA_PERSISTENT_RET",
|
||||
"AFL_FRIDA_STATS_FILE",
|
||||
"AFL_FRIDA_STATS_INTERVAL",
|
||||
"AFL_FRIDA_STATS_TRANSITIONS",
|
||||
"AFL_FUZZER_ARGS", // oss-fuzz
|
||||
"AFL_GDB",
|
||||
"AFL_GCC_ALLOWLIST",
|
||||
|
Loading…
x
Reference in New Issue
Block a user