/* Chrysalide - Outil d'analyse de fichiers binaires * rank.c - classement des blocs d'instructions * * Copyright (C) 2013 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 . */ #include "rank.h" #include #include #include "../blocks/flow.h" #include "../blocks/virtual.h" /* Classe le contenu d'un bloc d'instructions exécutées. */ static bool rank_flow_block(GFlowBlock *, BlockVisitOrder, const GInstrBlock *); /****************************************************************************** * * * Paramètres : block = bloc d'instructions concerné par la visite. * * order = indication quant au sens de visite. * * list = ensemble des blocs basiques à parcourir. * * * * Description : Classe le contenu d'un bloc d'instructions exécutées. * * * * Retour : true pour continuer la visite. * * * * Remarques : - * * * ******************************************************************************/ static bool rank_flow_block(GFlowBlock *block, BlockVisitOrder order, const GInstrBlock *list) { unsigned int next; /* Rang suivant obtenu */ GInstrBlock *links; /* Blocs liés au bloc courant */ GArchInstruction *last; /* Dernière instruction du bloc*/ 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 */ const mrange_t *range; /* Emplacement d'une cible */ GFlowBlock *target; /* Bloc ciblé par un lien */ unsigned int rank; /* Rang à constituer */ /* Si le bloc visité n'est pas basique... */ if (order != BVO_PENDING) return true; next = g_flow_block_get_rank(block) + 1; links = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); g_flow_block_get_boundary(block, NULL, &last); dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL); for (i = 0; i < dcount; i++) { range = g_arch_instruction_get_range(dests[i]); switch (types[i]) { case ILT_EXEC_FLOW: case ILT_CATCH_EXCEPTION: target = G_FLOW_BLOCK(g_instr_block_find_by_addr(list, get_mrange_addr(range), true)); assert(target != NULL); break; case ILT_JUMP: target = G_FLOW_BLOCK(g_instr_block_find_by_addr(list, get_mrange_addr(range), true)); /** * Les sauts ne se font pas toujours à l'intérieur d'une même fonction. * Par exemple sous ARM : * * 00008358 : * .... * 8362: f7ff bfcf b.w 8304 <_init+0x38> * .... * */ /* assert(target != NULL);*/ break; case ILT_CASE_JUMP: target = G_FLOW_BLOCK(g_instr_block_find_by_addr(links, get_mrange_addr(range), true)); assert(target != NULL); break; case ILT_JUMP_IF_TRUE: case ILT_JUMP_IF_FALSE: /** * Même dans les branches if/then/else, il n'y a pas forcément de groupe de blocs * associé. C'est par exemple le cas dans des constructions telles que celle de * la fonction __libc_csu_init() : * * if (...) * do * { * ... * } * while (...) * * ... * * Le code final est étiquetté comme étant le 'else' de la première condition, * donc au niveau de la condition de bouclage, il appartient déjà à un autre * et n'est donc pas réattribué une seconde fois. * */ if (links != NULL) target = G_FLOW_BLOCK(g_instr_block_find_by_addr(links, get_mrange_addr(range), true)); else target = NULL; /** * Le bloc visé ne se trouve pas toujours dans les blocs attachés : * * { bloc IF } * { bloc THEN } * { block NEXT } * * Le bloc NEXT est ici à rechercher dans la liste globale. */ if (target == NULL) target = G_FLOW_BLOCK(g_instr_block_find_by_addr(list, get_mrange_addr(range), true)); assert(target != NULL); break; default: target = NULL; break; } if (target != NULL) { rank = MAX(next, g_flow_block_get_rank(target)); g_flow_block_set_rank(target, rank); } } return true; } /****************************************************************************** * * * 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 : Classe les blocs des routines. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void rank_routines_blocks(GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id) { size_t i; /* Boucle de parcours */ GInstrBlock *main_block; /* Ensemble des blocs d'instr. */ for (i = 0; i < count; i++) { main_block = g_binary_routine_get_basic_blocks(routines[i]); g_instr_block_visit(main_block, (instr_block_visitor_cb)rank_flow_block, main_block); printf("===== BLOCK(S) xXXx ======\n"); bool visit_ranked_block(GInstrBlock *blk, BlockVisitOrder order, int *indent) { int i; switch (order) { case BVO_IN: case BVO_PENDING: for (i = 0; i < *indent; i++) printf(" "); printf("%p '%s'", blk, G_OBJECT_TYPE_NAME(blk)); if (G_IS_FLOW_BLOCK(blk)) { vmpa2t start; vmpa2t end; g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(blk), &start, &end); printf(" 0x%08x -> 0x%08x (rank = %u)", (unsigned int)start.virtual, (unsigned int)end.virtual, g_flow_block_get_rank(G_FLOW_BLOCK(blk))); } printf("\n"); if (order == BVO_IN) (*indent)++; break; case BVO_OUT: (*indent)--; break; } return true; } g_instr_block_visit(main_block, (instr_block_visitor_cb)visit_ranked_block, (int []){ 0 }); printf("\n"); } }