summaryrefslogtreecommitdiff
path: root/plugins/ropgadgets/finder.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-05-11 00:58:05 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-05-11 00:58:05 (GMT)
commit46bcc7f122245f22772fd3e38d16e6afa7bd5881 (patch)
treed3c2ba1a9999e373428954f24d0e60c1ea63b756 /plugins/ropgadgets/finder.c
parent1bda6c517d30d873ff0d92a96380946ef944c9ae (diff)
Provided a way to look for ROP gadgets in binary code.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@533 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'plugins/ropgadgets/finder.c')
-rw-r--r--plugins/ropgadgets/finder.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/plugins/ropgadgets/finder.c b/plugins/ropgadgets/finder.c
new file mode 100644
index 0000000..ff0c6ad
--- /dev/null
+++ b/plugins/ropgadgets/finder.c
@@ -0,0 +1,399 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * finder.c - recherche de gadgets pour ROP
+ *
+ * Copyright (C) 2015 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "finder.h"
+
+
+#include <string.h>
+
+
+#include <core/processors.h>
+
+
+#include <i18n.h>
+
+
+#include "helper_arm.h"
+
+
+
+/* Données utiles à transmettre */
+typedef struct _search_domain
+{
+ GBinFormat *format; /* Format du fichier binaire */
+ GBinContent *content; /* Contenu associé récupéré */
+ GArchProcessor *proc; /* Processeur idéal en place */
+ GProcContext *ctx; /* Contexte de désassemblage */
+
+ mrange_t *exe_ranges; /* Liste de zones exécutables */
+ size_t exe_count; /* Nombre de ces zones */
+
+ phys_t sum; /* Surface totale à parcourir */
+ size_t runs_count; /* Nombre de passages à faire */
+ size_t runs_done; /* Nombre de passages effectués*/
+
+} search_domain;
+
+
+/* Désassemble rapidement une instruction. */
+static GArchInstruction *disassemble_instruction_in_domain(const search_domain *, vmpa2t *);
+
+/* Désassemble en amont d'une position autant que possible. */
+static GArchInstruction *look_backward_for_gadgets(const search_domain *, const mrange_t *, const vmpa2t *, unsigned int);
+
+/* Etablit une liste de tous les gadgets présents. */
+static GArchInstruction **list_all_gadgets_in_domain(const search_domain *, unsigned int, update_search_progress_cb, GObject *, size_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : domain = ensemble d'auxiliaires à disposition. *
+* pos = tête de lecture pour le désassemblage. *
+* *
+* Description : Désassemble rapidement une instruction. *
+* *
+* Retour : Instruction créée ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GArchInstruction *disassemble_instruction_in_domain(const search_domain *domain, vmpa2t *pos)
+{
+ GArchInstruction *result; /* Instruction à retourner */
+ GProcContext *ctx; /* Contexte de désassemblage */
+
+ ctx = domain->ctx; /* TODO : copie */
+
+ result = g_arch_processor_disassemble_nextgen(domain->proc, ctx, domain->content, pos);
+
+ if (result != NULL)
+ {
+ g_arch_instruction_call_hook(result, IPH_LINK, domain->proc, ctx, domain->format);
+ g_arch_instruction_call_hook(result, IPH_POST, domain->proc, ctx, domain->format);
+ }
+
+ //g_object_unref(G_OBJECT(ctx)); /* TODO */
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : domain = ensemble d'auxiliaires à disposition. *
+* exe_range = couverture globale dont il ne faut pas sortir. *
+* ret = point de retour final déjà trouvé. *
+* max_depth = profondeur maximale des recherches. *
+* *
+* Description : Désassemble en amont d'une position autant que possible. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GArchInstruction *look_backward_for_gadgets(const search_domain *domain, const mrange_t *exe_range, const vmpa2t *ret, unsigned int max_depth)
+{
+ GArchInstruction *result; /* Liste de gagdets trouvées */
+ const phys_t *ins_sizes; /* Tailles potentielles */
+ size_t sizes_count; /* Quantité de tailles à tester*/
+ vmpa2t last; /* Dernier point de départ */
+ unsigned int i; /* Boucle de parcours #1 */
+ GArchInstruction *instr; /* Elément de gadget trouvé */
+ size_t k; /* Boucle de parcours #2 */
+ vmpa2t start; /* Point de départ courant */
+ vmpa2t end; /* Point d'arrivée obtenu */
+ phys_t diff; /* Volume de données traité */
+ mrange_t range; /* Couverture de l'instruction */
+
+ result = NULL;
+
+ ins_sizes = (phys_t []){ 2, 4 }; /* FIXME */
+ sizes_count = 2;
+
+ copy_vmpa(&last, ret);
+
+ /* On parcours jusqu'à la profondeur maximale */
+ for (i = 0; i < max_depth; i++)
+ {
+ instr = NULL;
+
+ for (k = 0; k < sizes_count && instr == NULL; k++)
+ {
+ copy_vmpa(&start, &last);
+ deminish_vmpa(&start, ins_sizes[k]);
+
+ /* Est-on toujours dans les clous ? */
+ if (!mrange_contains_addr(exe_range, &start)) break;
+
+ copy_vmpa(&end, &start);
+
+ instr = disassemble_instruction_in_domain(domain, &end);
+ if (instr == NULL) continue;
+
+ /* La jointure est-elle parfaite ? */
+
+ if (cmp_vmpa(&end, &last) != 0)
+ {
+ g_object_unref(G_OBJECT(instr));
+ instr = NULL;
+ continue;
+ }
+
+ /* S'il s'agit d'un point de retour, on laisse la main à une autre liste */
+
+ if (g_arch_instruction_is_return(instr))
+ {
+ g_object_unref(G_OBJECT(instr));
+ instr = NULL;
+ continue;
+ }
+
+ }
+
+ /* Aucune instruction n'a été trouvée à cette profondeur, on s'arrête donc */
+ if (instr == NULL) break;
+
+ copy_vmpa(&last, &start);
+
+ diff = compute_vmpa_diff(&end, &start);
+
+ init_mrange(&range, &start, diff);
+
+ g_arch_instruction_set_range(instr, &range);
+
+
+ g_arch_instruction_merge_lists(&result, &instr);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : domain = ensemble d'auxiliaires à disposition. *
+* max_depth = profondeur maximale des recherches. *
+* update = fonction de suivi mise à disposition. *
+* data = données à associer à une phase d'actualisation. *
+* count = nombre de gadgets trouvés. [OUT] *
+* *
+* Description : Etablit une liste de tous les gadgets présents. *
+* *
+* Retour : Liste de listes d'instructions, à libérer après usage. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GArchInstruction **list_all_gadgets_in_domain(const search_domain *domain, unsigned int max_depth, update_search_progress_cb update, GObject *data, size_t *count)
+{
+ GArchInstruction **result; /* Liste de listes à renvoyer */
+ phys_t done; /* Accumulation des quantités */
+ size_t i; /* Boucle de parcours #1 */
+ phys_t max; /* Borne d'un parcours */
+ phys_t k; /* Boucle de parcours #2 */
+ gdouble fraction; /* Progression générale */
+ vmpa2t ret; /* Emplacement du retour */
+ vmpa2t tmp; /* Copie de travail modifiable */
+ GArchInstruction *gadget; /* Nouveau gadget détecté */
+ phys_t diff; /* Volume de données traité */
+ mrange_t ins_range; /* Emplacement d'une instruct° */
+ vmpa2t end; /* Point d'arrivée obtenu */
+ GArchInstruction *new; /* Nouvelle liste de gadgets */
+
+ result = NULL;
+ *count = 0;
+
+ done = 0;
+
+ for (i = 0; i < domain->exe_count; i++)
+ {
+ max = get_mrange_length(&domain->exe_ranges[i]);
+
+ for (k = 0; k < max; k++)
+ {
+ /* Affichage de la progression */
+
+ fraction = 1.0 * (domain->runs_done * domain->sum + done + k);
+ fraction /= (domain->runs_count * domain->sum);
+
+ update(data, fraction);
+
+ /* Réception de la première / dernière instruction */
+
+ copy_vmpa(&ret, get_mrange_addr(&domain->exe_ranges[i]));
+ advance_vmpa(&ret, k);
+
+ copy_vmpa(&tmp, &ret);
+
+ gadget = disassemble_instruction_in_domain(domain, &tmp);
+ if (gadget == NULL) continue;
+
+ /* A-t-on bien affaire à une instruction de retour ? */
+
+ if (!g_arch_instruction_is_return(gadget))
+ {
+ g_object_unref(G_OBJECT(gadget));
+ continue;
+ }
+
+ /* Ne déborde-t-on pas dans une zone voisine ? */
+
+ diff = compute_vmpa_diff(&ret, &tmp);
+ init_mrange(&ins_range, &ret, diff);
+
+ compute_mrange_end_addr(&ins_range, &end);
+
+ if (!mrange_contains_mrange(&domain->exe_ranges[i], &ins_range))
+ {
+ g_object_unref(G_OBJECT(gadget));
+ continue;
+ }
+
+ /* Ajout d'un nouvel ensemble de gadgets */
+
+ g_arch_instruction_set_range(gadget, &ins_range);
+
+ //printf(" ROP @ 0x%08x / 0x%08x\n", gadget->range.addr.virtual, ret.virtual);
+
+ new = look_backward_for_gadgets(domain, &domain->exe_ranges[i], &ret, max_depth);
+
+ g_arch_instruction_merge_lists(&new, &gadget);
+
+ result = (GArchInstruction **)realloc(result, ++(*count) * sizeof(GArchInstruction *));
+ result[*count - 1] = new;
+
+ }
+
+ done += max;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = binaire dont le contenu est à traiter. *
+* max_depth = profondeur maximale des recherches. *
+* update = fonction de suivi mise à disposition. *
+* data = données à associer à une phase d'actualisation. *
+* count = nombre de gadgets trouvés. [OUT] *
+* *
+* Description : Etablit une liste de tous les gadgets présents. *
+* *
+* Retour : Liste de listes d'instructions, à libérer après usage. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+found_rop_list *list_all_gadgets(GBinFormat *format, unsigned int max_depth, update_search_progress_cb update, GObject *data, size_t *count)
+{
+ found_rop_list *result; /* Liste de listes à renvoyer */
+ const char *target; /* Sous-traitance requise */
+ search_domain domain; /* Outils pour la recherche */
+ GProcContext **contexts; /* Contextes pour recherches */
+ char **names; /* Désignations humaines liées */
+ size_t i; /* Boucle de parcours */
+
+ /* Constitution du socle commun */
+
+ g_object_ref(G_OBJECT(format));
+ domain.format = format;
+
+ domain.content = g_binary_format_get_conten_(format);
+
+ target = g_exe_format_get_target_machine(G_EXE_FORMAT(format));
+ domain.proc = get_arch_processor_for_type(target);
+
+ domain.exe_ranges = g_exe_format_get_x_ranges(G_EXE_FORMAT(format), &domain.exe_count);
+
+ /* Récupération des différents contextes */
+
+ if (strcmp(target, "armv7") == 0)
+ contexts = get_rop_contexts_for_arm(domain.proc, &names, count);
+
+ else
+ {
+ contexts = (GProcContext **)calloc(1, sizeof(GProcContext *));
+ names = (char **)calloc(1, sizeof(char *));
+ *count = 1;
+
+ contexts[0] = g_arch_processor_get_context(domain.proc);
+ names[0] = _("all");
+
+ }
+
+ /* Calcul de la surface totale à parcourir */
+
+ domain.sum = 0;
+
+ for (i = 0; i < domain.exe_count; i++)
+ domain.sum += get_mrange_length(&domain.exe_ranges[i]);
+
+ /* Détermination des différents parcours */
+
+ domain.runs_count = *count;
+
+ domain.runs_done = 0;
+
+ /* Parcours des différentes surfaces */
+
+ result = (found_rop_list *)calloc(*count, sizeof(found_rop_list));
+
+ for (i = 0; i < *count; i++)
+ {
+ result[i].category = names[i];
+
+ domain.ctx = contexts[i];
+
+ result[i].gadgets = list_all_gadgets_in_domain(&domain, max_depth, update, data, &result[i].count);
+
+ g_object_unref(G_OBJECT(domain.ctx));
+
+ domain.runs_done++;
+
+ }
+
+ free(names);
+ free(contexts);
+
+ free(domain.exe_ranges);
+
+ g_object_unref(G_OBJECT(domain.proc));
+ g_object_unref(G_OBJECT(domain.content));
+ g_object_unref(G_OBJECT(domain.format));
+
+ return result;
+
+}