diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2015-05-11 00:58:05 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2015-05-11 00:58:05 (GMT) |
commit | 46bcc7f122245f22772fd3e38d16e6afa7bd5881 (patch) | |
tree | d3c2ba1a9999e373428954f24d0e60c1ea63b756 /plugins/ropgadgets/finder.c | |
parent | 1bda6c517d30d873ff0d92a96380946ef944c9ae (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.c | 399 |
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; + +} |