/* OpenIDA - Outil d'analyse de fichiers binaires * binary.c - traitement des flots de code binaire * * Copyright (C) 2008-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 "binary.h" #include #include #include #include #include #include #include "binary-int.h" #include "routine.h" #include "binaries/file.h" #include "decomp/decompiler.h" #include "disass/disassembler.h" #include "../common/extstr.h" /* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ /* Initialise la classe des descriptions de fichier binaire. */ static void g_loaded_binary_class_init(GLoadedBinaryClass *); /* Initialise une description de fichier binaire. */ static void g_loaded_binary_init(GLoadedBinary *); /* Supprime toutes les références externes. */ static void g_loaded_binary_dispose(GLoadedBinary *); /* Procède à la libération totale de la mémoire. */ static void g_loaded_binary_finalize(GLoadedBinary *); /* Charge les parties intéressantes du binaire à partir d'XML. */ static bool g_loaded_binary_load_parts_from_xml(GLoadedBinary *, xmlXPathContextPtr, const char *); /* Ecrit les parties de valeur du binaire dans un fichier XML. */ static bool g_loaded_binary_save_parts(const GLoadedBinary *, xmlDocPtr, xmlXPathContextPtr, const char *); /* Acquitte la fin d'un désasemblage différé et complet. */ static void ack_completed_disassembly(GDelayedDisassembly *, GLoadedBinary *); /* Indique le type défini pour une description de fichier binaire. */ G_DEFINE_TYPE(GLoadedBinary, g_loaded_binary, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des descriptions de fichier binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_loaded_binary_class_init(GLoadedBinaryClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_loaded_binary_dispose; object->finalize = (GObjectFinalizeFunc)g_loaded_binary_finalize; g_signal_new("disassembly-done", G_TYPE_LOADED_BINARY, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GLoadedBinaryClass, disassembly_done), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /****************************************************************************** * * * Paramètres : binary = instance à initialiser. * * * * Description : Initialise une description de fichier binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_loaded_binary_init(GLoadedBinary *binary) { binary->text_display[BDT_ASM][0] = true; binary->text_display[BDT_ASM][1] = true; binary->text_display[BDT_GRAPH][0] = false; binary->text_display[BDT_GRAPH][1] = false; binary->lines_display = true; } /****************************************************************************** * * * Paramètres : binary = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_loaded_binary_dispose(GLoadedBinary *binary) { if (binary->format != NULL) g_object_unref(G_OBJECT(binary->format)); if (binary->proc != NULL) g_object_unref(G_OBJECT(binary->proc)); /* TODO... */ G_OBJECT_CLASS(g_loaded_binary_parent_class)->dispose(G_OBJECT(binary)); } /****************************************************************************** * * * Paramètres : binary = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_loaded_binary_finalize(GLoadedBinary *binary) { /* TODO */ G_OBJECT_CLASS(g_loaded_binary_parent_class)->finalize(G_OBJECT(binary)); } /****************************************************************************** * * * Paramètres : context = contexte pour les recherches XPath. * * path = chemin d'accès au noeud XML à lire. * * * * Description : Charge en mémoire le contenu d'un fichier à partir d'XML. * * * * Retour : Adresse de la représentation ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GLoadedBinary *g_loaded_binary_new_from_xml(xmlXPathContextPtr context, const char *path) { GLoadedBinary *result; /* Adresse à retourner */ char *type; /* Tupe de binaire à charger */ result = NULL; type = get_node_prop_value(context, path, "type"); if (strcmp(type, "file") == 0) result = g_loaded_binary_new_from_xml(context, path); free(type); if (result == NULL) return NULL; if (!g_loaded_binary_load_parts_from_xml(result, context, path)) goto glbnfx_error; return result; glbnfx_error: g_object_unref(G_OBJECT(result)); return NULL; } /****************************************************************************** * * * Paramètres : binary = élément binaire à traiter. * * xdoc = structure XML en cours d'édition. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès réservé au binaire. * * * * Description : Ecrit une sauvegarde du binaire dans un fichier XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_loaded_binary_save(const GLoadedBinary *binary, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path) { bool result; /* Bilan à faire remonter */ result = binary->save(binary, xdoc, context, path); /* Parties à désassembler */ result = g_loaded_binary_save_parts(binary, xdoc, context, path); return result; } /****************************************************************************** * * * Paramètres : context = contexte pour les recherches XPath. * * path = chemin d'accès au noeud XML à lire. * * * * Description : Charge les parties intéressantes du binaire à partir d'XML. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_load_parts_from_xml(GLoadedBinary *binary, xmlXPathContextPtr context, const char *path) { bool result; /* Bilan à retourner */ char *access; /* Chemin pour une sous-config.*/ xmlXPathObjectPtr xobjects; /* Cible d'une recherche */ int i; /* Boucle de parcours */ GBinPart *part; /* Partie binaire à traiter */ off_t offset; /* Position de cette partie */ vmpa_t addr; /* Adresse correspondante */ result = NULL; /* Parties à désassembler : default */ access = strdup(path); access = stradd(access, "/BinParts/Default/Part"); xobjects = get_node_xpath_object(context, access); for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobjects); i++) { part = g_binary_part_load_from_xml(NODE_FROM_PATH_OBJ(xobjects, i)); if (part != NULL) { g_binary_part_get_values(part, &offset, NULL, NULL); if (!g_exe_format_translate_offset_into_address(G_EXE_FORMAT(binary->format), offset, &addr)) { g_object_unref(G_OBJECT(part)); continue; } binary->parts_count[BPM_DEFAULT]++; binary->parts[BPM_DEFAULT] = (GBinPart **)realloc(binary->parts[BPM_DEFAULT], binary->parts_count[BPM_DEFAULT] * sizeof(GBinPart *)); binary->parts[BPM_DEFAULT][binary->parts_count[BPM_DEFAULT] - 1] = part; } } if(xobjects != NULL) xmlXPathFreeObject(xobjects); free(access); qsort(binary->parts[BPM_DEFAULT], binary->parts_count[BPM_DEFAULT], sizeof(GBinPart *), (__compar_fn_t)g_binary_part_compare); /* Parties à désassembler : routines */ access = strdup(path); access = stradd(access, "/BinParts/Routines/Part"); xobjects = get_node_xpath_object(context, access); for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobjects); i++) { part = g_binary_part_load_from_xml(NODE_FROM_PATH_OBJ(xobjects, i)); if (part != NULL) { g_binary_part_get_values(part, &offset, NULL, NULL); if (!g_exe_format_translate_offset_into_address(G_EXE_FORMAT(binary->format), offset, &addr)) { g_object_unref(G_OBJECT(part)); continue; } else g_binary_part_set_address(part, addr); binary->parts_count[BPM_ROUTINES]++; binary->parts[BPM_ROUTINES] = (GBinPart **)realloc(binary->parts[BPM_ROUTINES], binary->parts_count[BPM_ROUTINES] * sizeof(GBinPart *)); binary->parts[BPM_ROUTINES][binary->parts_count[BPM_ROUTINES] - 1] = part; } } if(xobjects != NULL) xmlXPathFreeObject(xobjects); free(access); qsort(binary->parts[BPM_ROUTINES], binary->parts_count[BPM_ROUTINES], sizeof(GBinPart *), (__compar_fn_t)g_binary_part_compare); /* Parties à désassembler : utilisateur */ access = strdup(path); access = stradd(access, "/BinParts/User/Part"); xobjects = get_node_xpath_object(context, access); for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobjects); i++) { part = g_binary_part_load_from_xml(NODE_FROM_PATH_OBJ(xobjects, i)); if (part != NULL) { g_binary_part_get_values(part, &offset, NULL, NULL); if (!g_exe_format_translate_offset_into_address(G_EXE_FORMAT(binary->format), offset, &addr)) { g_object_unref(G_OBJECT(part)); continue; } binary->parts_count[BPM_USER]++; binary->parts[BPM_USER] = (GBinPart **)realloc(binary->parts[BPM_USER], binary->parts_count[BPM_USER] * sizeof(GBinPart *)); binary->parts[BPM_USER][binary->parts_count[BPM_USER] - 1] = part; } } if(xobjects != NULL) xmlXPathFreeObject(xobjects); free(access); qsort(binary->parts[BPM_USER], binary->parts_count[BPM_USER], sizeof(GBinPart *), (__compar_fn_t)g_binary_part_compare); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à traiter. * * xdoc = structure XML en cours d'édition. * * context = contexte à utiliser pour les recherches. * * path = chemin d'accès réservé au binaire. * * * * Description : Ecrit les parties de valeur du binaire dans un fichier XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_save_parts(const GLoadedBinary *binary, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path) { bool result; /* Bilan à faire remonter */ char *access; /* Chemin d'accès à un élément */ xmlNodePtr node; /* Point d'insertion XML */ size_t i; /* Boucle de parcours */ result = true; if (binary->parts_count[BPM_DEFAULT] > 0) { access = strdup(path); access = stradd(access, "/BinParts/Default"); node = ensure_node_exist(xdoc, context, access); free(access); for (i = 0; i < binary->parts_count[BPM_DEFAULT] && result; i++) result &= g_binary_part_save_to_xml(binary->parts[BPM_DEFAULT][i], xdoc, node); } if (binary->parts_count[BPM_ROUTINES] > 0) { access = strdup(path); access = stradd(access, "/BinParts/Routines"); node = ensure_node_exist(xdoc, context, access); free(access); for (i = 0; i < binary->parts_count[BPM_ROUTINES] && result; i++) result &= g_binary_part_save_to_xml(binary->parts[BPM_ROUTINES][i], xdoc, node); } if (binary->parts_count[BPM_USER] > 0) { access = strdup(path); access = stradd(access, "/BinParts/User"); node = ensure_node_exist(xdoc, context, access); free(access); for (i = 0; i < binary->parts_count[BPM_USER] && result; i++) result &= g_binary_part_save_to_xml(binary->parts[BPM_USER][i], xdoc, node); } return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * parts = liste des zones binaires à analyser. * * model = modèle de sélection des zones. * * count = quantité de zones listées. * * * * Description : Définit les parties de binaire à analyser. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_set_parts(GLoadedBinary *binary, BinaryPartModel model, GBinPart **parts, size_t count) { qsort(parts, count, sizeof(GBinPart *), (__compar_fn_t)g_binary_part_compare); binary->parts[model] = parts; binary->parts_count[model] = count; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * model = modèle de sélection des zones. [OUT] * * count = quantité de zones listées. [OUT] * * * * Description : Fournit les parties de binaire analysées. * * * * Retour : Zones binaires à analyser. * * * * Remarques : - * * * ******************************************************************************/ GBinPart ***g_loaded_binary_get_parts(const GLoadedBinary *binary, BinaryPartModel *model, size_t **count) { *model = binary->model; *count = binary->parts_count; return binary->parts; } /****************************************************************************** * * * Paramètres : binary = élément binaire à traiter. * * * * Description : Lance l'analyse d'un élément binaire chargé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_analyse(GLoadedBinary *binary) { GBinPart **parts; /* Parties d'élément binaire */ size_t parts_count; /* Nombre de ces parties */ if (binary->parts_count[BPM_ROUTINES] > 0) binary->model = BPM_ROUTINES; if (binary->parts[binary->model] != NULL) { parts = binary->parts[binary->model]; parts_count = binary->parts_count[binary->model]; } else { if (binary->parts[BPM_DEFAULT] != NULL) { parts = binary->parts[BPM_DEFAULT]; parts_count = binary->parts_count[BPM_DEFAULT]; } else { parts = g_exe_format_get_parts(binary->format, &parts_count); qsort(parts, parts_count, sizeof(GBinPart *), (__compar_fn_t)g_binary_part_compare); } } disassemble_binary(binary, parts, parts_count, &binary->instrs, &binary->disass_buffer, ack_completed_disassembly); /* TODO : remme ! */ //ack_completed_disassembly(NULL, binary); } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * full = précise s'il s'agit d'une version longue ou non. * * * * Description : Fournit le fichier correspondant à l'élément binaire. * * * * Retour : Nom de fichier avec chemin absolu. * * * * Remarques : - * * * ******************************************************************************/ const char *g_loaded_binary_get_filename(const GLoadedBinary *binary, bool full) { return binary->get_filename(binary, full); } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * length = taille en octets des données chargées. [OUT] * * * * Description : Fournit les détails du contenu binaire chargé en mémoire. * * * * Retour : Pointeur vers le début des données. * * * * Remarques : - * * * ******************************************************************************/ bin_t *g_loaded_binary_get_data(const GLoadedBinary *binary, off_t *length) { if (length != NULL) *length = binary->bin_length; return binary->bin_data; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Fournit le format de fichier reconnu dans le contenu binaire.* * * * Retour : Adresse du format reconnu. * * * * Remarques : - * * * ******************************************************************************/ GExeFormat *g_loaded_binary_get_format(const GLoadedBinary *binary) { return binary->format; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Fournit les instructions issues du désassemblage. * * * * Retour : Instructions issues du désassemblage. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_loaded_binary_get_instructions(const GLoadedBinary *binary) { return binary->instrs; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Fournit le tampon associé au contenu assembleur d'un binaire.* * * * Retour : Tampon mis en place ou NULL si aucun (!). * * * * Remarques : - * * * ******************************************************************************/ GCodeBuffer *g_loaded_binary_get_disassembled_buffer(const GLoadedBinary *binary) { return binary->disass_buffer; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * type = type de représentation visée. * * * * Description : Indique si les adresses doivent apparaître dans le rendu. * * * * Retour : Consigne d'affichage. [OUT] * * * * Remarques : - * * * ******************************************************************************/ bool *g_loaded_binary_display_addresses_in_text(GLoadedBinary *binary, BinaryDisplayType type) { return &binary->text_display[type][0]; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * type = type de représentation visée. * * * * Description : Indique si le code doit apparaître dans le rendu. * * * * Retour : Consigne d'affichage. [OUT] * * * * Remarques : - * * * ******************************************************************************/ bool *g_loaded_binary_display_code_in_text(GLoadedBinary *binary, BinaryDisplayType type) { return &binary->text_display[type][1]; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * index = indice du fichier à retrouver. * * * * Description : Fournit le tampon associé au contenu d'un fichier source. * * * * Retour : Tampon mis en place ou NULL si aucun (!). * * * * Remarques : - * * * ******************************************************************************/ GCodeBuffer *g_loaded_binary_get_decompiled_buffer(const GLoadedBinary *binary, size_t index) { GCodeBuffer *result; /* Tampon à retourner */ if (binary->decbuf_count == 0) result = NULL; else if (index >= binary->decbuf_count) result = binary->dec_buffers[binary->defsrc]; else result = binary->dec_buffers[index]; return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Indique si les lignes doivent apparaître dans le rendu. * * * * Retour : Consigne d'affichage. [OUT] * * * * Remarques : - * * * ******************************************************************************/ bool *g_loaded_binary_display_decomp_lines(GLoadedBinary *binary) { return &binary->lines_display; } /****************************************************************************** * * * Paramètres : disass = travail de désassemblage mené à bien. * * binary = représentation de binaire à l'origine de l'opérat°. * * * * Description : Acquitte la fin d'un désasemblage différé et complet. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void ack_completed_disassembly(GDelayedDisassembly *disass, GLoadedBinary *binary) { //GRenderingLine *line; /* "Première" ligne de rendu */ size_t i; /* Boucle de parcours */ const char * const *files; /* Liste de fichiers source */ g_object_unref(G_OBJECT(disass)); /* Décompilation... */ files = g_binary_format_get_source_files(G_BIN_FORMAT(binary->format), &binary->decbuf_count, &binary->defsrc); if (binary->decbuf_count > 0) { binary->dec_buffers = (GCodeBuffer **)calloc(binary->decbuf_count, sizeof(GCodeBuffer *)); /* for (i = 0; i < binary->decbuf_count; i++) binary->dec_buffers[i] = decompile_all_from_file(binary, files[i]); */ } #if 0 g_rendering_line_merge(&binary->lines, &disass->lines); line = g_rendering_line_find_by_address(disass->lines, NULL, g_exe_format_get_entry_point(binary->format)); if (line != NULL) g_rendering_line_add_flag(line, RLF_ENTRY_POINT); /* On réintègre le flot premier */ #endif g_signal_emit_by_name(binary, "disassembly-done"); }