/* OpenIDA - Outil d'analyse de fichiers binaires * try_n_catch.c - support des exceptions chez Android * * Copyright (C) 2012 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 . */ #include "try_n_catch.h" #include #include #include #include <../i18n.h> /* Mémorisation d'un lien vers un gestionnaire */ typedef struct _caught_exception { GArchInstruction *instr; /* Première instruction visée */ char *desc; /* Nom de l'exception */ } caught_exception; /* Valide la zone couverte par le gestionnaire d'exceptions. */ static bool check_covered_area(const try_item *, const GBinRoutine *); /* Construit une liste pointant sur les différentes gestions. */ static caught_exception *build_destinations_list(GLoadedBinary *, const try_item *, const encoded_catch_handler_list *, const GBinRoutine *, size_t *); /* Rattache les gestionnaires d'exception à leur code couvert. */ static void attach_caught_code(GLoadedBinary *, const try_item *, const encoded_catch_handler_list *, const GBinRoutine *); /* Recherche et met en avant tous les gestionnaires d'exception. */ static void look_for_exception_handlers(GLoadedBinary *, const GDexFormat *, GDexMethod *); /****************************************************************************** * * * Paramètres : try = informations sur la gestion à consulter. * * routine = routine associée, pour validation. * * * * Description : Valide la zone couverte par le gestionnaire d'exceptions. * * * * Retour : Validité de la zone couverte. * * * * Remarques : - * * * ******************************************************************************/ static bool check_covered_area(const try_item *try, const GBinRoutine *routine) { off_t length; /* Taille de la zone de code */ vmpa_t covered_start; /* Début de la zone couverte */ vmpa_t covered_end; /* Fin de la zone couverte */ length = g_binary_routine_get_size(routine); covered_start = try->start_addr * sizeof(uint16_t); covered_end = covered_start + try->insn_count * sizeof(uint16_t); return (covered_end <= length); } /****************************************************************************** * * * Paramètres : binary = représentation binaire à traiter. * * try = informations sur la gestion à consulter. * * hlist = liste de tous les gestionnaires en place. * * routine = routine associée, pour l'accès au instructions. * * count = quantité de destinations trouvées. [OUT] * * * * Description : Construit une liste pointant sur les différentes gestions. * * * * Retour : Adresse des codes à lier systématiquement. * * * * Remarques : - * * * ******************************************************************************/ static caught_exception *build_destinations_list(GLoadedBinary *binary, const try_item *try, const encoded_catch_handler_list *hlist, const GBinRoutine *routine, size_t *count) { caught_exception *result; /* Liste à retourner */ GDexFormat *format; /* Format du binaire chargé */ vmpa_t start; /* Début du code de la routine */ GArchInstruction *instrs; /* Instructions Dalvik */ uleb128_t index; /* Indice du bon gestionnaire */ encoded_catch_handler *handlers; /* Groupe de gestionnaires */ leb128_t max; /* Quantité d'exception */ leb128_t i; /* Boucle de parcours */ vmpa_t handler_addr; /* Adresse du code de gestion */ GDataType *type; /* Type de l'exception */ format = G_DEX_FORMAT(g_loaded_binary_get_format(binary)); start = g_binary_routine_get_address(routine); instrs = g_loaded_binary_get_instructions(binary); instrs = g_arch_instruction_find_by_address(instrs, start, true); for (index = 0; index < hlist->size; index++) if (try->handler_off == hlist->list[index].offset) break; if (index == hlist->size) { *count = 0; return NULL; } handlers = &hlist->list[index]; max = leb128_abs(handlers->size); *count = max + (handlers->size < 0 ? 1 : 0); result = (caught_exception *)calloc(*count, sizeof(caught_exception)); *count = 0; for (i = 0; i < max; i++) { handler_addr = start + handlers->handlers[i].addr * sizeof(uint16_t); result[*count].instr = g_arch_instruction_find_by_address(instrs, handler_addr, true); if (result[*count].instr == NULL) continue; type = get_type_from_dex_pool(format, handlers->handlers[i].type_idx); result[*count].desc = g_data_type_to_string(type); (*count)++; } if (handlers->size < 0) { handler_addr = start + handlers->catch_all_addr * sizeof(uint16_t); result[*count].instr = g_arch_instruction_find_by_address(instrs, handler_addr, true); if (result[*count].instr != NULL) { result[*count].desc = strdup(_("default")); (*count)++; } } return result; } /****************************************************************************** * * * Paramètres : binary = représentation binaire à traiter. * * try = informations sur la gestion à consulter. * * handlers = liste de tous les gestionnaires en place. * * routine = routine associée, pour l'accès au instructions. * * * * Description : Rattache les gestionnaires d'exception à leur code couvert. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void attach_caught_code(GLoadedBinary *binary, const try_item *try, const encoded_catch_handler_list *handlers, const GBinRoutine *routine) { vmpa_t start; /* Début de la zone couverte */ vmpa_t end; /* Début de la zone couverte */ GArchInstruction *instrs; /* Instructions Dalvik */ GArchInstruction *first; /* Première instruction */ GArchInstruction *next; /* Dernière instruction + 1 */ GArchInstruction *prev; /* Instruction à détacher */ GArchInstruction *iter; /* Boucle de parcours */ size_t dests_count; /* Nombre de points d'arrivée */ caught_exception *dests; /* Points d'arrivée */ size_t i; /* Boucle de parcours */ start = g_binary_routine_get_address(routine); start += try->start_addr * sizeof(uint16_t); end = start + try->insn_count * sizeof(uint16_t); instrs = g_loaded_binary_get_instructions(binary); first = g_arch_instruction_find_by_address(instrs, start, true); next = g_arch_instruction_find_by_address(instrs, end, true); /* Si des détachements sont nécessaires... */ if (!g_arch_instruction_has_sources(first)) { prev = g_arch_instruction_get_prev_iter(instrs, first); g_arch_instruction_link_with(prev, first, ILT_EXEC_FLOW); } if (!g_arch_instruction_has_sources(next)) { prev = g_arch_instruction_get_prev_iter(instrs, next); g_arch_instruction_link_with(prev, next, ILT_EXEC_FLOW); } /* Détermination du code des exceptions */ dests = build_destinations_list(binary, try, handlers, routine, &dests_count); if (dests != NULL) { /* Rattachements */ for (iter = first; iter != NULL; iter = g_arch_instruction_get_next_iter(instrs, iter, end)) { if (!g_arch_instruction_has_destinations(iter)) continue; for (i = 0; i < dests_count; i++) g_arch_instruction_link_with(iter, dests[i].instr, ILT_CATCH_EXCEPTION); } /* Libération de la mémoire utilisée */ for (i = 0; i < dests_count; i++) free(dests[i].desc); free(dests); } } /****************************************************************************** * * * Paramètres : binary = représentation binaire à traiter. * * format = format du binaire Dex. * * method = méthode à analyser. * * * * Description : Recherche et met en avant tous les gestionnaires d'exception.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void look_for_exception_handlers(GLoadedBinary *binary, const GDexFormat *format, GDexMethod *method) { const code_item *body; /* Description du corps */ GBinRoutine *routine; /* Abstraction globale */ uint16_t i; /* Boucle de parcours */ body = g_dex_method_get_dex_body(method); if (body->tries_size == 0) return; routine = g_dex_method_get_routine(method); for (i = 0; i < body->tries_size; i++) { if (!check_covered_area(&body->tries[i], routine)) continue; attach_caught_code(binary, &body->tries[i], body->handlers, routine); } } /****************************************************************************** * * * Paramètres : binary = représentation binaire à traiter. * * * * Description : Traite tous les gestionnaires d'exception trouvés. * * * * Retour : true si une action a été menée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool process_exception_handlers(GLoadedBinary *binary) { GDexFormat *format; /* Format du binaire chargé */ size_t cls_count; /* Nombre de classes trouvées */ size_t i; /* Boucle de parcours #1 */ GDexClass *class; /* Classe à analyser */ size_t meth_count; /* Nombre de méthodes trouvées */ size_t j; /* Boucle de parcours #2 */ GDexMethod *method; /* Méthode à parcourir */ if (!G_IS_DEX_FORMAT(g_loaded_binary_get_format(binary))) return false; format = G_DEX_FORMAT(g_loaded_binary_get_format(binary)); cls_count = g_dex_format_count_classes(format); for (i = 0; i < cls_count; i++) { class = g_dex_format_get_class(format, i); meth_count = g_dex_class_count_methods(class, false); for (j = 0; j < meth_count; j++) { method = g_dex_class_get_method(class, false, j); look_for_exception_handlers(binary, format, method); } meth_count = g_dex_class_count_methods(class, true); for (j = 0; j < meth_count; j++) { method = g_dex_class_get_method(class, true, j); look_for_exception_handlers(binary, format, method); } } return true; }