From 028f8ced8f772d82a7efc522ec629bf4a5fff32d Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Aug 2021 17:28:40 +0100 Subject: Fixed coverage on OSX (dependency on pipe2) Removed use of 'realpath' in makefiles to fix OSX incompatibility Fixed handling of when prefetching should be enabled Snap the main binary during initialization to avoid stability issues with lazy loading Add support for configurable inline cache entries for FRIDA on x86/x64 Support for prefetching FRIDA backpatches on x86/x64 Improved stats support on x86/x64/aarch64 --- frida_mode/src/stats/stats.c | 423 +++++++++++++++++++++++++++++++------------ 1 file changed, 312 insertions(+), 111 deletions(-) (limited to 'frida_mode/src/stats/stats.c') diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 91a58741..7972b881 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -11,204 +11,405 @@ #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; } -void stats_config(void) { + if (stats_interval == 0) { return; } - stats_filename = getenv("AFL_FRIDA_STATS_FILE"); - stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); - if (getenv("AFL_FRIDA_STATS_TRANSITIONS") != NULL) { + guint64 current_time = g_get_monotonic_time(); + if ((current_time - stats_data->prev.stats_time) < stats_interval_us) { - stats_transitions = TRUE; + 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)); + } -void stats_init(void) { +static void gum_afl_stalker_stats_increment_total( + GumStalkerObserver *observer) { - stats_parent_pid = getpid(); + UNUSED_PARAMETER(observer); - OKF("Stats - file [%s]", stats_filename); - OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); + if (!entry_compiled) { return; } + stats_data->curr.total++; - if (stats_interval != 0 && stats_filename == NULL) { +} - FATAL( - "AFL_FRIDA_STATS_FILE must be specified if " - "AFL_FRIDA_STATS_INTERVAL is"); +static void gum_afl_stalker_stats_increment_call_imm( + GumStalkerObserver *observer) { - } + UNUSED_PARAMETER(observer); - if (stats_interval == 0) { stats_interval = 10; } + if (!entry_compiled) { return; } + stats_data->curr.call_imm++; - if (stats_filename == NULL) { return; } +} - if (!stats_is_supported_arch()) { +static void gum_afl_stalker_stats_increment_call_reg( + GumStalkerObserver *observer) { - FATAL("Stats is not supported on this architecture"); + UNUSED_PARAMETER(observer); - } + if (!entry_compiled) { return; } + stats_data->curr.call_reg++; - char *path = NULL; +} - if (stats_filename == NULL) { return; } +static void gum_afl_stalker_stats_increment_call_mem( + GumStalkerObserver *observer) { - if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); } + UNUSED_PARAMETER(observer); - path = g_canonicalize_filename(stats_filename, g_get_current_dir()); + if (!entry_compiled) { return; } + stats_data->curr.call_mem++; - OKF("Stats - path [%s]", path); +} - stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +static void gum_afl_stalker_stats_increment_excluded_call_reg( + GumStalkerObserver *observer) { - if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); } + UNUSED_PARAMETER(observer); - g_free(path); + if (!entry_compiled) { return; } + stats_data->curr.excluded_call_reg++; - size_t data_size = stats_data_size_arch(); +} - int shm_id = shmget(IPC_PRIVATE, data_size, IPC_CREAT | IPC_EXCL | 0600); - if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } +static void gum_afl_stalker_stats_increment_ret_slow_path( + GumStalkerObserver *observer) { - stats_data = shmat(shm_id, NULL, 0); - g_assert(stats_data != MAP_FAILED); + UNUSED_PARAMETER(observer); - /* - * Configure the shared memory region to be removed once the process dies. - */ - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { + if (!entry_compiled) { return; } + stats_data->curr.ret_slow_path++; - FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); +} - } +static void gum_afl_stalker_stats_increment_ret(GumStalkerObserver *observer) { - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(stats_data, '\0', data_size); + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.ret++; } -void stats_vprint(int fd, char *format, va_list ap) { +static void gum_afl_stalker_stats_increment_post_call_invoke( + GumStalkerObserver *observer) { - char buffer[4096] = {0}; - int len; + UNUSED_PARAMETER(observer); - if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + if (!entry_compiled) { return; } + stats_data->curr.post_call_invoke++; - len = strnlen(buffer, sizeof(buffer)); - IGNORED_RETURN(write(fd, buffer, len)); +} + +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++; } -void stats_print_fd(int fd, char *format, ...) { +static void gum_afl_stalker_stats_increment_jmp_imm( + GumStalkerObserver *observer) { - va_list ap; - va_start(ap, format); - stats_vprint(fd, format, ap); - va_end(ap); + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_imm++; } -void stats_print(char *format, ...) { +static void gum_afl_stalker_stats_increment_jmp_reg( + GumStalkerObserver *observer) { - va_list ap; - va_start(ap, format); - stats_vprint(stats_fd, format, ap); - va_end(ap); + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_reg++; } -void stats_write(void) { +static void gum_afl_stalker_stats_increment_jmp_mem( + GumStalkerObserver *observer) { - if (stats_parent_pid == getpid()) { return; } + UNUSED_PARAMETER(observer); - 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"); + if (!entry_compiled) { return; } + stats_data->curr.jmp_mem++; - 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); +static void gum_afl_stalker_stats_increment_jmp_cond_imm( + GumStalkerObserver *observer) { - stats_print("\n"); + UNUSED_PARAMETER(observer); - g_free(date_time_string); - g_date_time_unref(date_time); + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_imm++; - stats_write_arch(); +} - if (stats_transitions) { +static void gum_afl_stalker_stats_increment_jmp_cond_mem( + GumStalkerObserver *observer) { - 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"); + UNUSED_PARAMETER(observer); - 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); + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_mem++; - g_free(date_time_string); - g_date_time_unref(date_time); - gum_stalker_dump_counters(); +} - } +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++; } -void stats_on_fork(void) { +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) { - guint64 current_time; + 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"); + +} + +void stats_init(void) { + + OKF("Stats - file [%s]", stats_filename); + OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); + + if (stats_interval != 0 && stats_filename == NULL) { + + FATAL( + "AFL_FRIDA_STATS_FILE must be specified if " + "AFL_FRIDA_STATS_INTERVAL is"); + + } + + if (stats_interval == 0) { stats_interval = 10; } + stats_interval_us = stats_interval * MICRO_TO_SEC; if (stats_filename == NULL) { return; } - if (stats_interval == 0) { return; } + char *path = g_canonicalize_filename(stats_filename, g_get_current_dir()); + + OKF("Stats - path [%s]", path); - current_time = g_get_monotonic_time(); + stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); } - if ((current_time - stats_data->stats_last_time) > - (stats_interval * MICRO_TO_SEC)) { + g_free(path); - stats_write(); - stats_data->stats_last_time = current_time; + 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. + */ + 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, '\0', sizeof(stats_data_t)); + + starts_arch_init(); + } -void stats_collect(const cs_insn *instr, gboolean begin) { +void stats_print(char *format, ...) { - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(begin); + char buffer[4096] = {0}; + int len; - if (stats_fd < 0) { return; } + va_list ap; + va_start(ap, format); - if (begin) { stats_data->num_blocks++; } - stats_data->num_instructions++; + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } - stats_collect_arch(instr); + len = strnlen(buffer, sizeof(buffer)); + IGNORED_RETURN(write(stats_fd, buffer, len)); + va_end(ap); + +} + +void stats_on_fork(void) { + + stats_write(); + +} + +void stats_collect(const cs_insn *instr, gboolean begin) { + + if (!entry_compiled) { return; } + if (stats_filename == NULL) { return; } + stats_collect_arch(instr, begin); } -- cgit 1.4.1