/* OpenIDA - Outil d'analyse de fichiers binaires * format.c - support des différents formats binaires * * Copyright (C) 2009-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 "format.h" #include #include "format-int.h" #include "dex/dex.h" #include "dwarf/dwarf.h" #include "elf/elf.h" #include "java/java.h" #include "pe/pe.h" #include "../decomp/expr/block.h" #include "../gui/panels/log.h" #include "../plugins/pglist.h" #ifndef _ # define _(str) str #endif /* ------------------------ TRAITEMENT INDIVIDUEL DE FORMATS ------------------------ */ /* Initialise la classe des formats binaires génériques. */ static void g_binary_format_class_init(GBinFormatClass *); /* Initialise une instance de format binaire générique. */ static void g_binary_format_init(GBinFormat *); /* ----------------------- MANIPULATION D'ENSEMBLE DE FORMATS ----------------------- */ /* Format d'exécutables enregistré */ typedef struct _registered_format { const char *name; /* Désignation du format */ FormatType type; /* Type de format */ format_match_fc match; /* Procédure de reconnaissance */ format_load_fc load; /* Fonction de chargement */ } registered_format; /* Liste des formats d'exécutables enregistrés */ static registered_format _formats[FID_COUNT]; #define register_format(id, n, t, m, l) \ do \ { \ _formats[id].name = n; \ _formats[id].type = t; \ _formats[id].match = m; \ _formats[id].load = l; \ } \ while (0) /* ---------------------------------------------------------------------------------- */ /* TRAITEMENT INDIVIDUEL DE FORMATS */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un format binaire générique. */ G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des formats binaires génériques. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_format_class_init(GBinFormatClass *klass) { } /****************************************************************************** * * * Paramètres : format = instance à initialiser. * * * * Description : Initialise une instance de format binaire générique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_format_init(GBinFormat *format) { } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à consulter. * * content = contenu binaire à parcourir. * * length = taille du contenu fourni. * * * * Description : Définit le contenu binaire à analyser. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_format_set_content(GBinFormat *format, const bin_t *content, off_t length) { format->content = content; format->length = length; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à consulter. * * length = taille du contenu à fournir. [OUT] * * * * Description : Fournit une référence vers le contenu binaire analysé. * * * * Retour : Adresse du tampon contenant le contenu du binaire. * * * * Remarques : - * * * ******************************************************************************/ const bin_t *g_binary_format_get_content(const GBinFormat *format, off_t *length) { if (length != NULL) *length = format->length; return format->content; } /****************************************************************************** * * * Paramètres : format = informations chargées à compléter. * * symbol = symbole à ajouter à la liste. * * * * Description : Ajoute un symbole à la collection du format binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol) { format->symbols = (GBinSymbol **)realloc(format->symbols, ++format->symbols_count * sizeof(GBinSymbol *)); format->symbols[format->symbols_count - 1] = symbol; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * count = taille du tableau créé. [OUT] * * * * Description : Fournit la liste de tous les symboles détectés. * * * * Retour : Tableau créé ou NULL si aucun symbole trouvé. * * * * Remarques : - * * * ******************************************************************************/ GBinSymbol **g_binary_format_get_symbols(const GBinFormat *format, size_t *count) { *count = format->symbols_count; return format->symbols; } /****************************************************************************** * * * Paramètres : format = informations chargées à compléter. * * routine = routine à ajouter à la liste. * * * * Description : Ajoute une routine à la collection du format binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_format_add_routine(GBinFormat *format, GBinRoutine *routine) { format->routines = (GBinRoutine **)realloc(format->routines, ++format->routines_count * sizeof(GBinRoutine *)); format->routines[format->routines_count - 1] = routine; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * count = taille du tableau créé. [OUT] * * * * Description : Fournit le prototype de toutes les routines détectées. * * * * Retour : Tableau créé ou NULL si aucun symbole de routine trouvé. * * * * Remarques : - * * * ******************************************************************************/ GBinRoutine **g_binary_format_get_routines(const GBinFormat *format, size_t *count) { *count = format->routines_count; return format->routines; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * routine = routine à traiter. * * ctx = contexte de soutien à associer à l'opération. * * * * Description : Procède à la décompilation basique d'une routine donnée. * * * * Retour : Instructions créées et enregistrées, ou NULL si erreur. * * * * Remarques : - * * * ******************************************************************************/ GDecInstruction *g_binary_format_decompile_routine(const GBinFormat *format, GBinRoutine *routine, GDecContext *ctx) { GDecInstruction *result; /* Instructions décompilées */ GArchInstruction *instr; /* Instructions natives */ vmpa_t max; /* Première adresse à écarter */ GArchInstruction *iter; /* Boucle de parcours */ GDecInstruction *first; /* Première décompilation */ GDecInstruction *dinstr; /* Nouvelle décompilation */ result = NULL; instr = g_binary_routine_get_instructions(routine); max = g_binary_routine_get_address(routine) + g_binary_routine_get_size(routine); g_object_set_data(G_OBJECT(ctx), "format", format); g_object_set_data(G_OBJECT(ctx), "routine", routine); g_dec_context_set_max_address(ctx, max); for (iter = instr; iter != NULL; iter = g_arch_instruction_get_next_iter(instr, iter, max)) { g_arch_instruction_decompile(iter, ctx); } first = g_dec_context_get_decomp_instrs(ctx); for (dinstr = first; dinstr != NULL; dinstr = g_dec_instruction_get_next_iter(first, dinstr)) { if (result == NULL) result = g_expr_block_new(dinstr); else g_expr_block_add_item(G_EXPR_BLOCK(result), dinstr); } g_binary_routine_set_decomp_instructions(routine, result); return result; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * count = taille de la liste retournée. [OUT] * * defsrc = fichier de code principal. [OUT] * * * * Description : Fournit la liste des fichiers source détectés. * * * * Retour : Liste de noms de fichier ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ const char * const *g_binary_format_get_source_files(const GBinFormat *format, size_t *count, size_t *defsrc) { *count = format->src_count; *defsrc = format->def_source; return format->src_files; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * buffer = tampon mis à disposition pour la sortie. * * filename = nom du fichier source à cibler. * * * * Description : Procède à la décompilation complète du format. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_format_decompile(const GBinFormat *format, GCodeBuffer *buffer, const char *filename) { GBinRoutine **routines; size_t count; size_t i; GDecInstruction *instr; if (format->decompile != NULL) format->decompile(format, buffer, filename); routines = g_binary_format_get_routines(format, &count); for (i = 0; i < count; i++) { //printf(" -- %s --\n", g_binary_routine_get_name(routines[i])); //if (strcmp("cryptself", g_binary_routine_get_name(routines[i])) == 0) { instr = g_binary_routine_get_decomp_instructions(routines[i]); if (instr == NULL) continue; //g_dec_instruction_print(instr, buffer, NULL, g_java_output_new()); } } } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * label = étiquette du symbole si trouvé. [OUT] * * type = type du symbole trouvé. [OUT] * * address = adresse à cibler, puis décallage final. [OUT] * * * * Description : Recherche le symbole correspondant à une adresse. * * * * Retour : true si l'opération a été un succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_format_resolve_symbol(const GBinFormat *format, const char **label, SymbolType *type, vmpa_t *address) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ vmpa_t addr; /* Adresse de symbole */ off_t size; /* Taille du symole */ result = false; for (i = 0; i < format->symbols_count && !result; i++) { addr = g_binary_symbol_get_address(format->symbols[i]); size = g_binary_symbol_get_size(format->symbols[i]); if (addr <= *address && *address < (addr + size)) { *label = g_binary_symbol_to_string(format->symbols[i]); *type = g_binary_symbol_get_target_type(format->symbols[i]); *address -= addr; if (*type == STP_STRING) *label += *address; result = true; } } return result; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * label = étiquette du symbole si trouvé. [OUT] * * address = adresse à cibler, puis décallage final. [OUT] * * * * Description : Recherche une position dans une routine selon une adresse. * * * * Retour : true si l'opération a été un succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_format_resolve_relative_routine(const GBinFormat *format, const char **label, vmpa_t *address) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ vmpa_t addr; /* Adresse de symbole */ off_t size; /* Taille du symole */ result = false; for (i = 0; i < format->routines_count && !result; i++) { addr = g_binary_routine_get_address(format->routines[i]); size = g_binary_routine_get_size(format->routines[i]); if (addr <= *address && *address < (addr + size)) { *label = g_binary_routine_get_long_name(format->routines[i]); *address -= addr; result = true; } } return result; } /* ---------------------------------------------------------------------------------- */ /* MANIPULATION D'ENSEMBLE DE FORMATS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : - * * * * Description : Procède au chargement des formats binaires reconnus. * * * * Retour : true pour indiquer un chargement réussi, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool init_all_formats(void) { register_format(FID_DEX, _("Dalvik Executable"), FMT_EXEC, dex_is_matching, g_dex_format_new); //register_format(FID_DWARF, _("Dwarf"), FMT_DEBUG, dwarf_is_matching, g_dwarf_format_new); register_format(FID_ELF, _("ELF"), FMT_EXEC, elf_is_matching, g_elf_format_new); register_format(FID_JAVA, _("Java"), FMT_EXEC, java_is_matching, g_java_format_new); register_format(FID_PE, _("PE"), FMT_EXEC, pe_is_matching, g_pe_format_new); return true; } /****************************************************************************** * * * Paramètres : type = type de format recherché. * * filename = fichier d'origine des données initiales. * * content = contenu binaire à parcourir. [OUT] * * length = taille du contenu en question. [OUT] * * * * Description : Charge si possible un nouveau format binaire. * * * * Retour : Adresse du nouveau gestionnaire de format ou NULL si erreur. * * * * Remarques : - * * * ******************************************************************************/ GBinFormat *load_new_format(FormatType type, char *filename, bin_t **content, off_t *length) { GBinFormat *result; /* Adresse à retourner */ char *tmp; /* Nom de fichier modifiable */ GPluginModule **pglist; /* Liste de greffons */ size_t pgcount; /* Taille de cette liste */ size_t i; /* Boucle de parcours */ result = NULL; tmp = strdup(filename); pglist = get_all_plugins_for_action(PGA_FORMAT_MATCHER, &pgcount); if (pgcount > 0) { lnf_rescan: for (i = 0; i < pgcount; i++) switch (g_plugin_module_is_matching(pglist[i], &tmp, content, length)) { case MFA_MATCHED: /* FIXME */ break; case MFA_RELOAD: //goto lnf_rescan; break; default: break; } free(pglist); } if (tmp == NULL) free(tmp); for (i = 0; i < FID_COUNT && result == NULL; i++) if (_formats[i].type == type && _formats[i].match(type, *content, *length)) { log_variadic_message(LMT_INFO, _("%s is matching..."), _formats[i].name); result = _formats[i].load(*content, *length); } return result; }