Merge pull request #1075 from WorksButNotTested/test

Various New Features & Fixes
This commit is contained in:
van Hauser 2021-08-20 23:15:18 +02:00 committed by GitHub
commit ca9c87dd45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1459 additions and 662 deletions

View File

@ -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)"

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -4,6 +4,7 @@
#include "frida-gumjs.h"
extern gboolean prefetch_enable;
extern gboolean prefetch_backpatch;
void prefetch_config(void);
void prefetch_init(void);

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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)) {

View File

@ -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) {

View File

@ -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(

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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; }
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View 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

View File

@ -1,5 +1,5 @@
PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../../)/
ROOT:=$(PWD)../../../
BUILD_DIR:=$(PWD)build/
TEST_CMPLOG_SRC=$(PWD)cmplog.c

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
ROOT:=$(PWD)../../../
BUILD_DIR:=$(PWD)build/
TEST_DATA_DIR:=$(BUILD_DIR)in/

View File

@ -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

View File

@ -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

View File

@ -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 #######

View File

@ -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 $@ $<

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
ROOT:=$(PWD)../../../
BUILD_DIR:=$(PWD)build/
LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/

View File

@ -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) \

View File

@ -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 \

View File

@ -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

View File

@ -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 #######

View File

@ -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' \

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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",