#include #include #include #include #include #include "frida-gumjs.h" #include "config.h" #include "entry.h" #include "shm.h" #include "stalker.h" #include "stats.h" #include "util.h" #define MICRO_TO_SEC 1000000 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; void stats_write(void) { 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", 10); } void stats_init(void) { FOKF(cBLU "Stats" cRST " - " cGRN "file:" cYEL " [%s]", stats_filename == NULL ? " " : stats_filename); FOKF(cBLU "Stats" cRST " - " cGRN "interval:" cYEL " [%" G_GINT64_MODIFIER "u]", stats_interval); if (getenv("AFL_FRIDA_STATS_INTERVAL") != NULL && getenv("AFL_FRIDA_STATS_FILE") == NULL) { FFATAL( "AFL_FRIDA_STATS_FILE must be specified if " "AFL_FRIDA_STATS_INTERVAL is"); } stats_interval_us = stats_interval * MICRO_TO_SEC; if (stats_filename == NULL) { return; } char *path = g_canonicalize_filename(stats_filename, g_get_current_dir()); FOKF(cBLU "Stats" cRST " - " cGRN "path:" cYEL " [%s]", path == NULL ? " " : path); stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (stats_fd < 0) { FFATAL("Failed to open stats file '%s'", path); } g_free(path); GumStalkerObserver *observer = stalker_get_observer(); stats_observer_init(observer); stats_data = shm_create(sizeof(stats_data_t)); starts_arch_init(); } void stats_print(char *format, ...) { char buffer[4096] = {0}; int len; va_list ap; va_start(ap, format); 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_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); }