diff options
Diffstat (limited to 'frida_mode/src/cmplog/cmplog.c')
-rw-r--r-- | frida_mode/src/cmplog/cmplog.c | 139 |
1 files changed, 68 insertions, 71 deletions
diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 3df7d13d..a6c95ab0 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -10,18 +10,20 @@ #include "util.h" #define DEFAULT_MMAP_MIN_ADDR (32UL << 10) -#define FD_TMP_MAX_SIZE 65536 +#define MAX_MEMFD_SIZE (64UL << 10) extern struct cmp_map *__afl_cmp_map; - static GArray *cmplog_ranges = NULL; -static int fd_tmp = -1; -static ssize_t fd_tmp_size = 0; +static GHashTable * hash = NULL; + +static int memfd = -1; +static size_t memfd_size = 0; +static u8 scratch[MAX_MEMFD_SIZE] = {0}; static gboolean cmplog_range(const GumRangeDetails *details, gpointer user_data) { - UNUSED_PARAMETER(user_data); + GArray * cmplog_ranges = (GArray *)user_data; GumMemoryRange range = *details->range; g_array_append_val(cmplog_ranges, range); return TRUE; @@ -35,71 +37,95 @@ static gint cmplog_sort(gconstpointer a, gconstpointer b) { } -static int cmplog_create_temp(void) { +static void cmplog_get_ranges(void) { - const char *tmpdir = g_get_tmp_dir(); - OKF("CMPLOG Temporary directory: %s", tmpdir); - gchar *fname = g_strdup_printf("%s/frida-cmplog-XXXXXX", tmpdir); - OKF("CMPLOG Temporary file template: %s", fname); - int fd = mkstemp(fname); - OKF("CMPLOG Temporary file: %s", fname); + OKF("CMPLOG - Collecting ranges"); + + cmplog_ranges = + g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); + gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, cmplog_ranges); + g_array_sort(cmplog_ranges, cmplog_sort); - if (fd < 0) { + for (guint i = 0; i < cmplog_ranges->len; i++) { - FATAL("Failed to create temp file: %s, errno: %d", fname, errno); + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); } - if (unlink(fname) < 0) { + g_array_free(cmplog_ranges, TRUE); - FATAL("Failed to unlink temp file: %s (%d), errno: %d", fname, fd, errno); +} - } +void cmplog_init(void) { + + if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } + + cmplog_get_ranges(); - if (ftruncate(fd, 0) < 0) { + for (guint i = 0; i < cmplog_ranges->len; i++) { - FATAL("Failed to ftruncate temp file: %s (%d), errno: %d", fname, fd, - errno); + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + OKF("CMPLOG Range - %3u: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X", + i, range->base_address, range->base_address + range->size); } - g_free(fname); + memfd = syscall(__NR_memfd_create, "cmplog_memfd", 0); + if (memfd < 0) { - return fd; + FATAL("Failed to create_memfd, errno: %d", errno); + + } + + hash = g_hash_table_new (g_direct_hash, g_direct_equal); + if (hash == NULL) { + FATAL("Failed to g_hash_table_new, errno: %d", errno); + } } -void cmplog_init(void) { +static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, + GumAddress outer_base, GumAddress outer_limit) { - if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } + return (inner_base >= outer_base && inner_limit <= outer_limit); - cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); - gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL); - g_array_sort(cmplog_ranges, cmplog_sort); +} - for (guint i = 0; i < cmplog_ranges->len; i++) { +gboolean cmplog_test_addr(guint64 addr, size_t size) { - GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); - OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER - "X", - range->base_address, range->base_address + range->size); + if (g_hash_table_contains(hash, (gpointer)addr)) { return true; } + if (memfd_size > MAX_MEMFD_SIZE) { + if (lseek(memfd, 0, SEEK_SET) < 0) { + FATAL("CMPLOG - Failed lseek, errno: %d", errno); + } } /* - * We can't use /dev/null or /dev/zero for this since it appears that they - * don't validate the input buffer. Persumably as an optimization because they - * don't actually write any data. The file will be deleted on close. + * Our address map can change (e.g. stack growth), use write as a fallback to + * validate our address. + */ + ssize_t written = syscall(__NR_write, memfd, (void *)addr, size); + if (written < 0 && errno != EFAULT && errno != 0) { + FATAL("CMPLOG - Failed __NR_write, errno: %d", errno); + } + /* + * If the write succeeds, then the buffer must be valid otherwise it would + * return EFAULT */ - fd_tmp = cmplog_create_temp(); + if (written > 0) { memfd_size += written; } -} + if ((size_t)written == size) { + if (!g_hash_table_add (hash, (gpointer)addr)) { + FATAL("Failed - g_hash_table_add"); + } + return true; + } -static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, - GumAddress outer_base, GumAddress outer_limit) { - return (inner_base >= outer_base && inner_limit <= outer_limit); + return false; } gboolean cmplog_is_readable(guint64 addr, size_t size) { @@ -125,6 +151,7 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) { for (guint i = 0; i < cmplog_ranges->len; i++) { GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + GumAddress outer_base = range->base_address; GumAddress outer_limit = outer_base + range->size; @@ -133,37 +160,7 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) { } - /* - * Our address map can change (e.g. stack growth), use write as a fallback to - * validate our address. - */ - ssize_t written = syscall(__NR_write, fd_tmp, (void *)addr, size); - - /* - * If the write succeeds, then the buffer must be valid otherwise it would - * return EFAULT - */ - if (written > 0) { - - fd_tmp_size += written; - if (fd_tmp_size > FD_TMP_MAX_SIZE) { - - /* - * Truncate the file, we don't want our temp file to continue growing! - */ - if (ftruncate(fd_tmp, 0) < 0) { - - FATAL("Failed to truncate fd_tmp (%d), errno: %d", fd_tmp, errno); - - } - - fd_tmp_size = 0; - - } - - if ((size_t)written == size) { return true; } - - } + if (cmplog_test_addr(addr, size)) { return true; } return false; |