diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2013-02-10 09:56:11 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2013-02-10 09:56:11 (GMT) |
commit | 34e1a14aced520ba06ee1b81cfd7710e97c1643f (patch) | |
tree | 2657c22041ab954bb2165553f71141b7843956a2 /src/analysis/disass/loop.c | |
parent | 3467b0cdb09976faccc6dbef09315cc38dbe6fb5 (diff) |
Improved the disassembling process by handling loops in code.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@339 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/analysis/disass/loop.c')
-rw-r--r-- | src/analysis/disass/loop.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c new file mode 100644 index 0000000..301f084 --- /dev/null +++ b/src/analysis/disass/loop.c @@ -0,0 +1,283 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * loop.c - détection des boucles dans du code machine + * + * Copyright (C) 2013 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * 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 "loop.h" + + +#include <malloc.h> +#include <stdlib.h> +#include <string.h> + + + +/* Suivi du flot d'exécution */ +typedef struct _exec_flow +{ + vmpa_t *steps; /* Jalons dans l'exécution */ + size_t count; /* Quantité de ces points */ + +} exec_flow; + + +/* Initialise un flot d'exécution. */ +static exec_flow *create_exec_flow(void); + +/* Réalise la copie d'un flot d'exécution. */ +static exec_flow *dup_exec_flow(const exec_flow *); + +/* Efface de la mémoire un flot d'exécution. */ +static void delete_exec_flow(exec_flow *); + +/* Recherche si le chemin d'exécution a déjà mené à une adresse. */ +static bool is_new_exec_flow(const exec_flow *, vmpa_t); + +/* Ajoute une adresse jalon dans un flot d'exécution. */ +static void add_step_into_exec_flow(exec_flow *, vmpa_t); + +/* Suit un flot d'exécution à la recherche de boucles. */ +static void track_loops_in_code(GArchInstruction *, vmpa_t, vmpa_t, exec_flow *); + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Initialise un flot d'exécution. * +* * +* Retour : Flot d'exécution nouveau. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static exec_flow *create_exec_flow(void) +{ + exec_flow *result; /* Flot vierge à retourner */ + + result = (exec_flow *)calloc(1, sizeof(exec_flow)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = jalons de l'exécution à dupliquer. * +* * +* Description : Réalise la copie d'un flot d'exécution. * +* * +* Retour : Flot d'exécution copié. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static exec_flow *dup_exec_flow(const exec_flow *src) +{ + exec_flow *result; /* Copie à retourner */ + + result = (exec_flow *)calloc(1, sizeof(exec_flow)); + + result->steps = (vmpa_t *)malloc(src->count * sizeof(vmpa_t)); + memcpy(result->steps, src->steps, src->count * sizeof(vmpa_t)); + + result->count = src->count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : flow = jalons de l'exécution à supprimer. * +* * +* Description : Efface de la mémoire un flot d'exécution. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_exec_flow(exec_flow *flow) +{ + free(flow->steps); + + free(flow); + +} + + +/****************************************************************************** +* * +* Paramètres : flow = ensemble des jalons de l'exécution du code. * +* addr = adresse d'un nouvel embranchement. * +* * +* Description : Recherche si le chemin d'exécution a déjà mené à une adresse.* +* * +* Retour : true si l'instruction est visitée pour la première fois. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool is_new_exec_flow(const exec_flow *flow, vmpa_t addr) +{ + void *ret; /* Conclusion d'une recherche */ + + ret = bsearch(&addr, flow->steps, flow->count, + sizeof(vmpa_t), (__compar_fn_t)compare_vmpa); + + return (ret == NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : flow = jalons de l'exécution du code à compléter. * +* addr = adresse d'un nouvel embranchement. * +* * +* Description : Ajoute une adresse jalon dans un flot d'exécution. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void add_step_into_exec_flow(exec_flow *flow, vmpa_t addr) +{ + flow->steps = (vmpa_t *)realloc(flow->steps, ++flow->count * sizeof(vmpa_t)); + flow->steps[flow->count - 1] = addr; + + qsort(flow->steps, flow->count, sizeof(vmpa_t), (__compar_fn_t)compare_vmpa); + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'instructions à parcourir. * +* start = adresse du début de l'analyse. * +* end = adresse de fin de la routine traitée. * +* flow = ensemble des jalons de l'exécution du code. * +* * +* Description : Suit un flot d'exécution à la recherche de boucles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void track_loops_in_code(GArchInstruction *list, vmpa_t start, vmpa_t end, exec_flow *flow) +{ + GArchInstruction *iter; /* Boucle de parcours */ + GArchInstruction **dests; /* Instr. visée par une autre */ + InstructionLinkType *types; /* Type de lien entre lignes */ + size_t dcount; /* Nombre de liens de dest. */ + size_t i; /* Boucle de parcours */ + vmpa_t addr; /* Prochaine adresse de saut */ + exec_flow *next_flow; /* Suite de l'exécution */ + + add_step_into_exec_flow(flow, start); + + for (iter = g_arch_instruction_find_by_address(list, start, true); + iter != NULL; + iter = g_arch_instruction_get_next_iter(list, iter, end)) + { + dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL); + + for (i = 0; i < dcount; i++) + switch (types[i]) + { + case ILT_LOOP: + break; + + case ILT_CALL: + case ILT_CATCH_EXCEPTION: + break; + + default: + g_arch_instruction_get_location(dests[i], NULL, NULL, &addr); + + if (!is_new_exec_flow(flow, addr)) + types[i] = ILT_LOOP; + + else + { + next_flow = dup_exec_flow(flow); + track_loops_in_code(list, addr, end, next_flow); + delete_exec_flow(next_flow); + } + + break; + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'instructions à relier. * +* routines = prototypes existants à insérer. * +* count = quantité de ces prototypes. * +* statusbar = barre de statut avec progression à mettre à jour.* +* id = identifiant du message affiché à l'utilisateur. * +* * +* Description : Détecte les boucles dans du code machine. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void detect_loops_in_code(GArchInstruction *list, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) +{ + size_t i; /* Boucle de parcours */ + vmpa_t start; /* Adresse de départ */ + vmpa_t end; /* Adresse de fin */ + exec_flow *flow; /* Flot d'exécution à suivre */ + + for (i = 0; i < count; i++) + { + start = g_binary_routine_get_address(routines[i]); + end = start + g_binary_routine_get_size(routines[i]); + + flow = create_exec_flow(); + track_loops_in_code(list, start, end, flow); + delete_exec_flow(flow); + + gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count); + + } + +} |