about summary refs log tree commit diff
path: root/frida_mode/src/cmplog/cmplog.c
diff options
context:
space:
mode:
Diffstat (limited to 'frida_mode/src/cmplog/cmplog.c')
-rw-r--r--frida_mode/src/cmplog/cmplog.c139
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;