about summary refs log tree commit diff
path: root/frida_mode/src/ranges.c
diff options
context:
space:
mode:
Diffstat (limited to 'frida_mode/src/ranges.c')
-rw-r--r--frida_mode/src/ranges.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c
new file mode 100644
index 00000000..fc14710f
--- /dev/null
+++ b/frida_mode/src/ranges.c
@@ -0,0 +1,395 @@
+// 0x123-0x321
+// module.so
+
+#include "ranges.h"
+#include "debug.h"
+
+#define MAX_RANGES 20
+
+typedef struct {
+
+  gchar *         suffix;
+  GumMemoryRange *range;
+  gboolean        done;
+
+} convert_name_ctx_t;
+
+typedef struct {
+
+  GumStalker *stalker;
+  GArray *    array;
+
+} include_range_ctx_t;
+
+GArray * ranges = NULL;
+gboolean exclude_ranges = false;
+
+static void convert_address_token(gchar *token, GumMemoryRange *range) {
+
+  gchar **tokens;
+  int     token_count;
+  tokens = g_strsplit(token, "-", 2);
+  for (token_count = 0; tokens[token_count] != NULL; token_count++)
+    ;
+
+  if (token_count != 2) {
+
+    FATAL("Invalid range (should have two addresses seperated by a '-'): %s\n",
+          token);
+
+  }
+
+  gchar *from_str = tokens[0];
+  gchar *to_str = tokens[1];
+
+  if (!g_str_has_prefix(from_str, "0x")) {
+
+    FATAL("Invalid range: %s - Start address should have 0x prefix: %s\n",
+          token, from_str);
+
+  }
+
+  if (!g_str_has_prefix(to_str, "0x")) {
+
+    FATAL("Invalid range: %s - End address should have 0x prefix: %s\n", token,
+          to_str);
+
+  }
+
+  from_str = &from_str[2];
+  to_str = &to_str[2];
+
+  for (char *c = from_str; *c != '\0'; c++) {
+
+    if (!g_ascii_isxdigit(*c)) {
+
+      FATAL("Invalid range: %s - Start address not formed of hex digits: %s\n",
+            token, from_str);
+
+    }
+
+  }
+
+  for (char *c = to_str; *c != '\0'; c++) {
+
+    if (!g_ascii_isxdigit(*c)) {
+
+      FATAL("Invalid range: %s - End address not formed of hex digits: %s\n",
+            token, to_str);
+
+    }
+
+  }
+
+  guint64 from = g_ascii_strtoull(from_str, NULL, 16);
+  if (from == 0) {
+
+    FATAL("Invalid range: %s - Start failed hex conversion: %s\n", token,
+          from_str);
+
+  }
+
+  guint64 to = g_ascii_strtoull(to_str, NULL, 16);
+  if (to == 0) {
+
+    FATAL("Invalid range: %s - End failed hex conversion: %s\n", token, to_str);
+
+  }
+
+  if (from >= to) {
+
+    FATAL("Invalid range: %s - Start (0x%016" G_GINT64_MODIFIER
+          "x) must be less than end "
+          "(0x%016" G_GINT64_MODIFIER "x)\n",
+          token, from, to);
+
+  }
+
+  range->base_address = from;
+  range->size = to - from;
+
+  g_strfreev(tokens);
+
+}
+
+static gboolean convert_name_token_for_module(const GumModuleDetails *details,
+                                              gpointer user_data) {
+
+  convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
+  if (details->path == NULL) { return true; };
+
+  if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
+
+  OKF("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
+      "x-0x%016" G_GINT64_MODIFIER "x %s",
+      ctx->suffix, details->range->base_address,
+      details->range->base_address + details->range->size, details->path);
+
+  *ctx->range = *details->range;
+  ctx->done = true;
+  return false;
+
+}
+
+static void convert_name_token(gchar *token, GumMemoryRange *range) {
+
+  gchar *            suffix = g_strconcat("/", token, NULL);
+  convert_name_ctx_t ctx = {.suffix = suffix, .range = range, .done = false};
+
+  gum_process_enumerate_modules(convert_name_token_for_module, &ctx);
+  if (!ctx.done) { FATAL("Failed to resolve module: %s\n", token); }
+  g_free(suffix);
+
+}
+
+static void convert_token(gchar *token, GumMemoryRange *range) {
+
+  if (g_strrstr(token, "-")) {
+
+    convert_address_token(token, range);
+
+  } else {
+
+    convert_name_token(token, range);
+
+  }
+
+  OKF("Converted token: %s -> 0x%016" G_GINT64_MODIFIER
+      "x-0x%016" G_GINT64_MODIFIER "x\n",
+      token, range->base_address, range->base_address + range->size);
+
+}
+
+static gboolean include_ranges(const GumRangeDetails *details,
+                               gpointer               user_data) {
+
+  include_range_ctx_t *ctx = (include_range_ctx_t *)user_data;
+  GArray *             array = (GArray *)ctx->array;
+  GumAddress           base = details->range->base_address;
+  GumAddress limit = details->range->base_address + details->range->size;
+
+  OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER
+      "x-0x%016" G_GINT64_MODIFIER "x",
+      base, limit);
+
+  for (int i = 0; i < array->len; i++) {
+
+    GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i);
+    GumAddress      range_base = range->base_address;
+    GumAddress      range_limit = range->base_address + range->size;
+
+    /* Before the region */
+    if (range_limit < base) { continue; }
+
+    /* After the region */
+    if (range_base > limit) {
+
+      GumMemoryRange exclude = {.base_address = base, .size = limit - base};
+      OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER
+          "x",
+          base, limit);
+      gum_stalker_exclude(ctx->stalker, &exclude);
+      return true;
+
+    }
+
+    /* Overlap the start of the region */
+    if (range_base < base) {
+
+      /* Range contains the region */
+      if (range_limit > limit) {
+
+        return true;
+
+      } else {
+
+        base = range_limit;
+        continue;
+
+      }
+
+      /* Overlap the end of the region */
+
+    } else {
+
+      GumMemoryRange exclude = {.base_address = base,
+                                .size = range_base - base};
+      OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER
+          "x",
+          base, range_base);
+      gum_stalker_exclude(ctx->stalker, &exclude);
+      /* Extend past the end of the region */
+      if (range_limit >= limit) {
+
+        return true;
+
+        /* Contained within the region */
+
+      } else {
+
+        base = range_limit;
+        continue;
+
+      }
+
+    }
+
+  }
+
+  GumMemoryRange exclude = {.base_address = base, .size = limit - base};
+  OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x",
+      base, limit);
+  gum_stalker_exclude(ctx->stalker, &exclude);
+  return true;
+
+}
+
+gint range_sort(gconstpointer a, gconstpointer b) {
+
+  return ((GumMemoryRange *)a)->base_address -
+         ((GumMemoryRange *)b)->base_address;
+
+}
+
+static gboolean print_ranges(const GumRangeDetails *details,
+                             gpointer               user_data) {
+
+  if (details->file == NULL) {
+
+    OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X",
+        details->range->base_address,
+        details->range->base_address + details->range->size);
+
+  } else {
+
+    OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER
+        "X %s(0x%016" G_GINT64_MODIFIER "x)",
+        details->range->base_address,
+        details->range->base_address + details->range->size,
+        details->file->path, details->file->offset);
+
+  }
+
+  return true;
+
+}
+
+void ranges_init(GumStalker *stalker) {
+
+  char *         showmaps;
+  char *         include;
+  char *         exclude;
+  char *         list;
+  gchar **       tokens;
+  int            token_count;
+  GumMemoryRange range;
+
+  int i;
+
+  showmaps = getenv("AFL_FRIDA_DEBUG_MAPS");
+  include = getenv("AFL_FRIDA_INST_RANGES");
+  exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES");
+
+  if (showmaps) {
+
+    gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL);
+
+  }
+
+  if (include != NULL && exclude != NULL) {
+
+    FATAL(
+        "Cannot specifify both AFL_FRIDA_INST_RANGES and "
+        "AFL_FRIDA_EXCLUDE_RANGES");
+
+  }
+
+  if (include == NULL && exclude == NULL) { return; }
+
+  list = include == NULL ? exclude : include;
+  exclude_ranges = include == NULL ? true : false;
+
+  tokens = g_strsplit(list, ",", MAX_RANGES);
+
+  for (token_count = 0; tokens[token_count] != NULL; token_count++)
+    ;
+
+  ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count);
+
+  for (i = 0; i < token_count; i++) {
+
+    convert_token(tokens[i], &range);
+    g_array_append_val(ranges, range);
+
+  }
+
+  g_array_sort(ranges, range_sort);
+
+  /* Check for overlaps */
+  for (i = 1; i < token_count; i++) {
+
+    GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1);
+    GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
+    GumAddress      prev_limit = prev->base_address + prev->size;
+    GumAddress      curr_limit = curr->base_address + curr->size;
+    if (prev_limit > curr->base_address) {
+
+      FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER
+            "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER
+            "x-0x%016" G_GINT64_MODIFIER "x",
+            prev->base_address, prev_limit, curr->base_address, curr_limit);
+
+    }
+
+  }
+
+  for (i = 0; i < token_count; i++) {
+
+    GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
+    GumAddress      curr_limit = curr->base_address + curr->size;
+    OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x",
+        i, curr->base_address, curr_limit);
+
+  }
+
+  if (include == NULL) {
+
+    for (i = 0; i < token_count; i++) {
+
+      gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i));
+
+    }
+
+  } else {
+
+    include_range_ctx_t ctx = {.stalker = stalker, .array = ranges};
+    gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx);
+
+  }
+
+  g_strfreev(tokens);
+
+}
+
+gboolean range_is_excluded(gpointer address) {
+
+  int        i;
+  GumAddress test = GUM_ADDRESS(address);
+
+  if (ranges == NULL) { return false; }
+
+  for (i = 0; i < ranges->len; i++) {
+
+    GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
+    GumAddress      curr_limit = curr->base_address + curr->size;
+
+    if (test < curr->base_address) { return !exclude_ranges; }
+
+    if (test < curr_limit) { return exclude_ranges; }
+
+  }
+
+  return !exclude_ranges;
+
+}
+