/* Chrysalide - Outil d'analyse de fichiers binaires * binary.c - traitement des flots de code binaire * * Copyright (C) 2009-2019 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide 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. * * Chrysalide 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 Chrysalide. If not, see . */ #include "binary.h" #include #include #include #include #include #include #include #include "loaded-int.h" #include "routine.h" #include "disass/disassembler.h" #include "../arch/storage.h" #include "../common/extstr.h" #include "../common/cpp.h" #include "../common/xdg.h" #include "../core/collections.h" #include "../core/logs.h" #include "../core/params.h" #include "../core/processors.h" #include "../format/known.h" #include "../glibext/gbinarycursor.h" #include "../glibext/gloadedpanel.h" #include "../gtkext/easygtk.h" #include "../gtkext/gtkblockdisplay.h" #include "../gtkext/gtkdisplaypanel.h" #include "../gtkext/gtkgraphdisplay.h" #include "../gtkext/hexdisplay.h" /* ------------------------ ENCADREMENTS D'UN BINAIRE CHARGE ------------------------ */ /* Description de fichier binaire (instance) */ struct _GLoadedBinary { GLoadedContent parent; /* A laisser en premier */ bool use_remote; /* Enregistrements distants ? */ char *remote_host; /* Nom du serveur distant */ char *remote_port; /* Port du serveur distant */ GAnalystClient *client; /* Enregistrements courants */ GList *collections; /* Ensemble de modifications */ GExeFormat *format; /* Format du binaire */ GArchProcessor *proc; /* Architecture du binaire */ GBufferCache *disass_cache; /* Instructions lisibles */ //GCodeBuffer **dec_buffers; /* Sources sous forme de texte */ size_t decbuf_count; /* Taille des tableaux */ size_t defsrc; /* Fichier source principal */ GDisplayOptions *options[BVW_COUNT]; /* Options d'affichage */ vmpa2t *old_gotos; /* Conservation de destinations*/ size_t goto_count; /* Taille de cette liste */ GMutex goto_access; /* Encadrement des accès */ }; /* Description de fichier binaire (classe) */ struct _GLoadedBinaryClass { GLoadedContentClass parent; /* A laisser en premier */ }; /* 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 *); /* ------------------------- INFORMATIONS D'ENREGISTREMENTS ------------------------- */ /* Charge en mémoire les formes d'enregistrement du XML. */ static bool g_loaded_binary_load_storage(GLoadedBinary *, xmlXPathContext *, const char *); /* Ecrit les formes d'enregistrement du binaire dans du XML. */ static bool g_loaded_binary_save_storage(const GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *); /* Etablit une connexion au serveur interne en tant que client. */ static bool g_loaded_binary_connect_internal(GLoadedBinary *); /* Etablit une connexion à un serveur distant comme client. */ static bool g_loaded_binary_connect_remote(GLoadedBinary *); /* -------------------------- MANIPULATION DES COLLECTIONS -------------------------- */ /* -------------------- SAUVEGARDE ET RESTAURATION DE PARAMETRES -------------------- */ /* Charge en mémoire les anciennes destinations visitées. */ static bool g_loaded_binary_load_old_gotos(GLoadedBinary *, xmlXPathContext *, const char *); /* Ecrit les anciennes destinations visitées dans du XML. */ static bool g_loaded_binary_save_old_gotos(GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *); /* ---------------------- GESTION SOUS FORME DE CONTENU CHARGE ---------------------- */ /* Interprète un contenu binaire chargé avec un appui XML. */ static bool g_loaded_binary_restore(GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *); /* Ecrit une sauvegarde du binaire dans un fichier XML. */ static bool g_loaded_binary_save(GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *); /* Fournit le contenu représenté de l'élément chargé. */ static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *); /* Décrit la nature du contenu reconnu pour l'élément chargé. */ static char *g_loaded_binary_get_content_class(const GLoadedBinary *, bool); /* Assure le désassemblage en différé. */ static bool g_loaded_binary_analyze(GLoadedBinary *, bool, bool, wgroup_id_t, GtkStatusStack *); /* Prend note d'une variation des instructions désassemblées. */ static void on_binary_processor_changed(GArchProcessor *, GArchInstruction *, gboolean, GLoadedBinary *); /* Fournit le désignation associée à l'élément chargé. */ static char *g_loaded_binary_describe(const GLoadedBinary *, bool); /* Détermine le nombre de vues disponibles pour un contenu. */ static unsigned int g_loaded_binary_count_views(const GLoadedBinary *); /* Fournit le nom d'une vue donnée d'un contenu chargé. */ static char *g_loaded_binary_get_view_name(const GLoadedBinary *, unsigned int); /* Met en place la vue initiale pour un contenu binaire. */ static GtkWidget *g_loaded_binary_build_default_view(GLoadedBinary *); /* Met en place la vue demandée pour un contenu binaire. */ static GtkWidget *g_loaded_binary_build_view(GLoadedBinary *, unsigned int); /* Retrouve l'indice correspondant à la vue donnée d'un contenu. */ static unsigned int g_loaded_binary_get_view_index(GLoadedBinary *, GtkWidget *); /* Fournit toutes les options d'affichage pour un contenu. */ static GDisplayOptions *g_loaded_binary_get_display_options(const GLoadedBinary *, unsigned int); /* ---------------------------------------------------------------------------------- */ /* ENCADREMENTS D'UN BINAIRE CHARGE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour une description de fichier binaire. */ G_DEFINE_TYPE(GLoadedBinary, g_loaded_binary, G_TYPE_LOADED_CONTENT); /****************************************************************************** * * * 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 */ GLoadedContentClass *loaded; /* Forme parente de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_loaded_binary_dispose; object->finalize = (GObjectFinalizeFunc)g_loaded_binary_finalize; loaded = G_LOADED_CONTENT_CLASS(klass); loaded->restore = (restore_content_fc)g_loaded_binary_restore; loaded->save = (save_content_fc)g_loaded_binary_save; loaded->get_content = (get_content_fc)g_loaded_binary_get_content; loaded->get_content_class = (get_content_class_fc)g_loaded_binary_get_content_class; loaded->analyze = (analyze_loaded_fc)g_loaded_binary_analyze; loaded->describe = (describe_loaded_fc)g_loaded_binary_describe; loaded->count_views = (count_loaded_views_fc)g_loaded_binary_count_views; loaded->get_view_name = (get_loaded_view_name_fc)g_loaded_binary_get_view_name; loaded->build_def_view = (build_loaded_def_view_fc)g_loaded_binary_build_default_view; loaded->build_view = (build_loaded_view_fc)g_loaded_binary_build_view; loaded->get_view_index = (get_loaded_view_index_fc)g_loaded_binary_get_view_index; loaded->get_options = (get_loaded_options_fc)g_loaded_binary_get_display_options; } /****************************************************************************** * * * Paramètres : binary = instance à initialiser. * * * * Description : Initialise une description de fichier binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_loaded_binary_init(GLoadedBinary *binary) { binary->use_remote = false; binary->remote_host = strdup("localhost"); binary->remote_port = strdup("1337"); binary->collections = create_collections_list(); attach_binary_to_collections(binary->collections, binary); binary->options[BVW_HEX] = g_display_options_new(); g_display_options_add(binary->options[BVW_HEX], _("Physical offset"), true); binary->options[BVW_BLOCK] = g_display_options_new(); g_display_options_add(binary->options[BVW_BLOCK], _("Physical offset"), true); g_display_options_add(binary->options[BVW_BLOCK], _("Virtual address"), true); g_display_options_add(binary->options[BVW_BLOCK], _("Binary code"), false); binary->options[BVW_GRAPH] = g_display_options_new(); g_display_options_add(binary->options[BVW_GRAPH], _("Physical offset"), false); g_display_options_add(binary->options[BVW_GRAPH], _("Virtual address"), false); g_display_options_add(binary->options[BVW_GRAPH], _("Binary code"), false); g_mutex_init(&binary->goto_access); } /****************************************************************************** * * * 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) { BinaryView i; /* Boucle de parcours */ g_clear_object(&binary->client); delete_collections_list(&binary->collections); g_clear_object(&binary->format); g_clear_object(&binary->proc); g_clear_object(&binary->disass_cache); for (i = 0; i < BVW_COUNT; i++) g_clear_object(&binary->options[i]); g_mutex_clear(&binary->goto_access); 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) { free(binary->remote_host); free(binary->remote_port); G_OBJECT_CLASS(g_loaded_binary_parent_class)->finalize(G_OBJECT(binary)); } /****************************************************************************** * * * Paramètres : format = format d'exécutable établi. * * * * Description : Interprète un contenu binaire chargé. * * * * Retour : Adresse de la représentation ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GLoadedContent *g_loaded_binary_new(GExeFormat *format) { GLoadedBinary *result; /* Adresse à retourner */ const char *arch; /* Architecture d'exécution */ GArchProcessor *proc; /* Architecture du binaire */ result = NULL; /* Architecture visée */ arch = g_exe_format_get_target_machine(format); if (arch == NULL) { log_simple_message(LMT_INFO, _("Unknown architecture")); goto exit; } proc = get_arch_processor_for_key(arch); if (proc == NULL) { log_variadic_message(LMT_ERROR, _("Unable to load the required processor (%s)"), arch); goto exit; } /* Mise en place complète */ result = g_object_new(G_TYPE_LOADED_BINARY, NULL); result->format = format; result->proc = proc; exit: return G_LOADED_CONTENT(result); } /* ---------------------------------------------------------------------------------- */ /* INFORMATIONS D'ENREGISTREMENTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : binary = élément binaire à traiter. * * context = contexte pour les recherches XPath. * * path = chemin d'accès au noeud XML à lire. * * * * Description : Charge en mémoire les formes d'enregistrement du XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_load_storage(GLoadedBinary *binary, xmlXPathContext *context, const char *path) { bool result; /* Bilan à faire remonter */ char *storage_path; /* Partie "Enregistrement" */ char *value; /* Valeur lue à partie du XML */ char *access; /* Chemin d'accès à un élément */ char *port; /* Port de communication */ result = true; storage_path = strdup(path); storage_path = stradd(storage_path, "/Storage"); value = get_node_prop_value(context, storage_path, "remote"); if (value == NULL) goto glbls_no_storage_config; binary->use_remote = (strcmp(value, "true") == 0); free(value); /* Serveur distant */ access = strdup(storage_path); access = stradd(access, "/RemoteServer"); value = get_node_prop_value(context, access, "port"); if (value == NULL) goto glbls_features; port = value; value = get_node_prop_value(context, access, "host"); if (value == NULL) { free(port); goto glbls_features; } g_loaded_binary_set_remote_server(binary, value, port); free(value); free(port); glbls_features: free(access); if (binary->use_remote) g_loaded_binary_set_remote_storage_usage(binary, true); glbls_no_storage_config: free(storage_path); 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 formes d'enregistrement du binaire dans du XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_save_storage(const GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path) { bool result; /* Bilan à faire remonter */ char *storage_path; /* Partie "Enregistrement" */ char *access; /* Chemin d'accès à un élément */ result = true; storage_path = strdup(path); storage_path = stradd(storage_path, "/Storage"); result &= add_string_attribute_to_node(xdoc, context, storage_path, "remote", binary->use_remote ? "true" : "false"); /* Serveur distant */ access = strdup(storage_path); access = stradd(access, "/RemoteServer"); result &= add_string_attribute_to_node(xdoc, context, access, "host", binary->remote_host); result &= add_string_attribute_to_node(xdoc, context, access, "port", binary->remote_port); free(access); free(storage_path); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Détermine si tous les enregistrements sont locaux ou non. * * * * Retour : Statut de l'utilisation du serveur local. * * * * Remarques : - * * * ******************************************************************************/ bool g_loaded_binary_use_remote_storage(const GLoadedBinary *binary) { return binary->use_remote; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * use = statut de l'utilisation du serveur distant. * * * * Description : Définit si tous les enregistrements sont locaux ou non. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_set_remote_storage_usage(GLoadedBinary *binary, bool use) { binary->use_remote = use; g_clear_object(&binary->client); if (use) g_loaded_binary_connect_remote(binary); } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * host = nom du serveur distant à contacter. [OUT] * * port = port de communication avec le serveur distant. [OUT]* * * * Description : Identifie le serveur distant associé au binaire courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_get_remote_server(const GLoadedBinary *binary, const char **host, const char **port) { *host = binary->remote_host; *port = binary->remote_port; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * host = nom du serveur distant à contacter. * * port = port de communication avec le serveur distant. * * * * Description : Définit le serveur distant associé au binaire courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_set_remote_server(GLoadedBinary *binary, const char *host, const char *port) { free(binary->remote_host); binary->remote_host = strdup(host); free(binary->remote_port); binary->remote_port = strdup(port); } /****************************************************************************** * * * Paramètres : binary = élément binaire à manipuler. * * * * Description : Etablit une connexion au serveur interne en tant que client. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_connect_internal(GLoadedBinary *binary) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu bianire manipulé */ const gchar *checksum; /* Identifiant de binaire */ /* Détermination de l'identifiant */ content = g_known_format_get_content(G_KNOWN_FORMAT(binary->format)); checksum = g_binary_content_get_checksum(content); g_object_unref(G_OBJECT(content)); /* Tentative de connexion */ binary->client = g_analyst_client_new(checksum, "NULL", binary->collections, NULL); result = g_hub_client_start_internal(G_HUB_CLIENT(binary->client)); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à manipuler. * * * * Description : Etablit une connexion à un serveur distant comme client. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_connect_remote(GLoadedBinary *binary) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu bianire manipulé */ const gchar *checksum; /* Identifiant de binaire */ assert(binary->client == NULL); /* Détermination de l'identifiant */ content = g_known_format_get_content(G_KNOWN_FORMAT(binary->format)); checksum = g_binary_content_get_checksum(content); g_object_unref(G_OBJECT(content)); /* Tentative de connexion */ binary->client = g_analyst_client_new(checksum, "NULL", binary->collections, NULL); result = g_hub_client_start_remote(G_HUB_CLIENT(binary->client), binary->remote_host, binary->remote_port, true); if (!result) { log_variadic_message(LMT_ERROR, _("Failed to connect to remote host '%s:%s'"), binary->remote_host, binary->remote_port); g_clear_object(&binary->client); } return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à manipuler. * * * * Description : Sauvegarde le cache des instructions désassemblées. * * * * Retour : Bilan préliminaire de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_loaded_binary_save_cache(const GLoadedBinary *binary) { bool result; /* Bilan à faire remonter */ GArchProcessor *proc; /* Processeur concerné */ GBinContent *content; /* Contenu brut représenté */ const gchar *id; /* Identifiant court et unique */ GAsmStorage *storage; /* Cache propre à constituer */ proc = g_loaded_binary_get_processor(binary); content = g_loaded_binary_get_content(binary); id = g_binary_content_get_checksum(content); storage = g_asm_storage_new_compressed(proc, id); g_object_unref(G_OBJECT(content)); g_object_unref(G_OBJECT(proc)); if (storage != NULL) { g_signal_connect(G_OBJECT(storage), "saved", G_CALLBACK(g_object_unref), NULL); g_asm_storage_save(storage); result = true; } else result = false; return result; } /* ---------------------------------------------------------------------------------- */ /* MANIPULATION DES COLLECTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Fournit un client assurant la liaison avec un serveur. * * * * Retour : Client connecté ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GAnalystClient *g_loaded_binary_get_client(const GLoadedBinary *binary) { GAnalystClient *result; /* Instance à retourner */ result = binary->client; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * count = taille de la liste constituée. [OUT] * * * * Description : Fournit l'ensemble des collections utilisées par un binaire. * * * * Retour : Liste de collections en place à libérer après usage. * * * * Remarques : - * * * ******************************************************************************/ GDbCollection **g_loaded_binary_get_collections(const GLoadedBinary *binary, size_t *count) { GDbCollection **result; /* Liste à retourner */ GList *c; /* Boucle de parcours #1 */ size_t i; /* Boucle de parcours #2 */ *count = g_list_length(binary->collections); if (*count == 0) result = NULL; else { result = malloc(*count * sizeof(GDbCollection *)); for (c = g_list_first(binary->collections), i = 0; c != NULL; c = g_list_next(c), i++) { assert(i < *count); result[i] = G_DB_COLLECTION(c->data); g_object_ref(G_OBJECT(result[i])); } } return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * feature = fonctionnalité assurée par la collection visée. * * * * Description : Trouve une collection assurant une fonctionnalité donnée. * * * * Retour : Collection trouvée ou NULL. * * * * Remarques : Le résultat est à déréfrencer après usage. * * * ******************************************************************************/ GDbCollection *g_loaded_binary_find_collection(const GLoadedBinary *binary, DBFeatures feature) { GDbCollection *result; /* Collection à retourner */ result = find_collection_in_list(binary->collections, feature); if (result != NULL) g_object_ref(G_OBJECT(result)); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * item = élémnent à pousser vers un serveur de collection. * * * * Description : Demande l'intégration d'une modification dans une collection.* * * * Retour : Bilan partiel de l'opération demandée. * * * * Remarques : L'appelant perd la propriété de l'élément à ajouté. * * * ******************************************************************************/ bool g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item) { bool result; /* Bilan à faire remonter */ GAnalystClient *client; /* Liaison à utiliser */ client = g_loaded_binary_get_client(binary); if (client == NULL) { log_simple_message(LMT_ERROR, _("No connection to a server in order to forward the item")); result = false; } else { result = g_analyst_client_add_item(client, item); g_object_unref(G_OBJECT(client)); } g_object_unref(G_OBJECT(item)); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * timestamp = date du dernier élément à garder comme actif. * * * * Description : Spécifie la bordure temporelle limite des activations. * * * * Retour : true si la commande a bien été envoyée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_loaded_binary_set_last_active(GLoadedBinary *binary, timestamp_t timestamp) { bool result; /* Bilan à retourner */ result = true; if (binary->client != NULL) result = g_analyst_client_set_last_active(binary->client, timestamp); else { log_simple_message(LMT_ERROR, _("No connection to a server found in order to set timestamp")); result = false; } return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Fournit le format de fichier reconnu dans le contenu binaire.* * * * Retour : Instance du format reconnu. * * * * Remarques : - * * * ******************************************************************************/ GExeFormat *g_loaded_binary_get_format(const GLoadedBinary *binary) { GExeFormat *result; /* Instance à retourner */ result = binary->format; g_object_ref(G_OBJECT(result)); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Fournit le processeur de l'architecture liée au binaire. * * * * Retour : Instance du processeur associé. * * * * Remarques : - * * * ******************************************************************************/ GArchProcessor *g_loaded_binary_get_processor(const GLoadedBinary *binary) { GArchProcessor *result; /* Instance à retourner */ result = binary->proc; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; } /****************************************************************************** * * * 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 : - * * * ******************************************************************************/ GBufferCache *g_loaded_binary_get_disassembly_cache(const GLoadedBinary *binary) { GBufferCache *result; /* Instance à retourner */ result = binary->disass_cache; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; } /* ---------------------------------------------------------------------------------- */ /* SAUVEGARDE ET RESTAURATION DE PARAMETRES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : binary = élément binaire à traiter. * * context = contexte pour les recherches XPath. * * path = chemin d'accès au noeud XML à lire. * * * * Description : Charge en mémoire les anciennes destinations visitées. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_load_old_gotos(GLoadedBinary *binary, xmlXPathContext *context, const char *path) { bool result; /* Bilan à faire remonter */ char *top_access; /* Chemin d'accès principal */ xmlXPathObjectPtr xobject; /* Cible d'une recherche */ size_t count; /* Nombre de contenus premiers */ size_t i; /* Boucle de parcours */ char *access; /* Chemin d'accès à un élément */ char *value; /* Valeur lue à partie du XML */ bool is_virt; /* Détermination de l'utile */ vmpa2t *new; /* Nouvelle destination */ result = true; asprintf(&top_access, "%s/OldGotos/Target", path); xobject = get_node_xpath_object(context, top_access); count = XPATH_OBJ_NODES_COUNT(xobject); for (i = 0; i < count; i++) { asprintf(&access, "%s/OldGotos/Target[position()=%zu]", path, i + 1); /* Type de destination */ value = get_node_prop_value(context, access, "type"); if (value == NULL) { result = false; break; } is_virt = (strcmp(value, "virt") == 0); free(value); /* Adresse de destination */ value = get_node_prop_value(context, access, "location"); if (value == NULL) { result = false; break; } if (is_virt) new = string_to_vmpa_virt(value); else new = string_to_vmpa_phy(value); free(value); /* Intégration */ binary->old_gotos = realloc(binary->old_gotos, ++binary->goto_count * sizeof(vmpa2t)); copy_vmpa(&binary->old_gotos[binary->goto_count - 1], new); delete_vmpa(new); free(access); } if(xobject != NULL) xmlXPathFreeObject(xobject); free(top_access); 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 anciennes destinations visitées dans du XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_save_old_gotos(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path) { bool result; /* Bilan à faire remonter */ size_t i; /* Boucle de parcours */ char *access; /* Chemin d'accès à un élément */ const vmpa2t *addr; /* Adresse de destination */ bool is_virt; /* Détermination de l'utile */ VMPA_BUFFER(loc); /* Version humaintement lisible*/ result = true; g_mutex_lock(&binary->goto_access); for (i = 0; i < binary->goto_count && result; i++) { asprintf(&access, "%s/OldGotos/Target[position()=%zu]", path, i + 1); result = (ensure_node_exist(xdoc, context, access) != NULL); addr = &binary->old_gotos[i]; is_virt = has_virt_addr(addr); if (result) result = add_string_attribute_to_node(xdoc, context, access, "type", is_virt ? "virt" : "phys"); if (result) { if (is_virt) vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL); else vmpa2_phys_to_string(addr, MDS_UNDEFINED, loc, NULL); result = add_string_attribute_to_node(xdoc, context, access, "location", loc); } free(access); } g_mutex_unlock(&binary->goto_access); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * new = nouvelle destination à conserver en mémoire. * * * * Description : Complète la liste des destinations déjà visitées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_remember_new_goto(GLoadedBinary *binary, const vmpa2t *new) { size_t previous_count; /* Sauvegarde de la taille */ size_t i; /* Boucle de parcours */ g_mutex_lock(&binary->goto_access); /* Mise en avant de la nouvelle ancienne destination */ binary->old_gotos = realloc(binary->old_gotos, ++binary->goto_count * sizeof(vmpa2t)); if (binary->goto_count > 1) memmove(&binary->old_gotos[1], &binary->old_gotos[0], (binary->goto_count - 1) * sizeof(vmpa2t)); copy_vmpa(&binary->old_gotos[0], new); /* Suppression de la même destination à une autre position */ previous_count = binary->goto_count; for (i = 1; i < binary->goto_count; i++) if (cmp_vmpa(&binary->old_gotos[i], new) == 0) { if ((i + 1) < binary->goto_count) memmove(&binary->old_gotos[i], &binary->old_gotos[i + 1], (binary->goto_count - i - 1) * sizeof(vmpa2t)); binary->goto_count--; i--; } if (previous_count != binary->goto_count) binary->old_gotos = realloc(binary->old_gotos, binary->goto_count * sizeof(vmpa2t)); g_mutex_unlock(&binary->goto_access); } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * count = nombre d'éléments dans la liste renvoyée. * * * * Description : Fournit la liste des anciennes destinations déjà visitées. * * * * Retour : Liste de destinations à libérer de la mémoire ou NULL. * * * * Remarques : - * * * ******************************************************************************/ vmpa2t *g_loaded_binary_get_old_gotos(GLoadedBinary *binary, size_t *count) { vmpa2t *result; /* Liste à renvoyer */ size_t i; /* Boucle de parcours */ g_mutex_lock(&binary->goto_access); *count = binary->goto_count; if (*count == 0) result = NULL; else { result = malloc(*count * sizeof(vmpa2t)); for (i = 0; i < *count; i++) copy_vmpa(&result[i], &binary->old_gotos[i]); } g_mutex_unlock(&binary->goto_access); return result; } /* ---------------------------------------------------------------------------------- */ /* GESTION SOUS FORME DE CONTENU CHARGE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * 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 : Interprète un contenu binaire chargé avec un appui XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_restore(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path) { bool result; /* Bilan à faire remonter */ /* Elément divers associés au binaire */ result = g_loaded_binary_load_storage(binary, context, path); if (result) result = g_loaded_binary_load_old_gotos(binary, context, path); 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 une sauvegarde du binaire dans un fichier XML. * * * * Retour : true si l'opération a bien tourné, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_save(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path) { bool result; /* Bilan à faire remonter */ GBinContent *content; /* Contenu brut à manipuler */ const gchar *hash; /* Empreinte d'un contenu */ char *key; /* Support associé au contenu */ /* Mise en cache des instructions */ result = g_loaded_binary_save_cache(binary); /* Elément divers associés au binaire */ if (result) { content = g_loaded_content_get_content(G_LOADED_CONTENT(binary)); hash = g_binary_content_get_checksum(content); result = add_string_attribute_to_node(xdoc, context, path, "hash", hash); g_object_unref(G_OBJECT(content)); } /* if (result) { key = g_loaded_content_get_content_class(G_LOADED_CONTENT(binary)); result = add_string_attribute_to_node(xdoc, context, path, "format", key); free(key); } if (result) { key = g_arch_processor_get_key(binary->proc); result = add_string_attribute_to_node(xdoc, context, path, "arch", key); free(key); } */ if (result) result = g_loaded_binary_save_storage(binary, xdoc, context, path); if (result) result = g_loaded_binary_save_old_gotos(binary, xdoc, context, path); /* Sauvegarde côté serveur */ if (result) g_analyst_client_save(binary->client); return result; } /****************************************************************************** * * * Paramètres : binary = élément chargé à manipuler. * * * * Description : Fournit le contenu représenté de l'élément chargé. * * * * Retour : Contenu représenté. * * * * Remarques : - * * * ******************************************************************************/ static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *binary) { GBinContent *result; /* Contenu interne à renvoyer */ result = g_known_format_get_content(G_KNOWN_FORMAT(binary->format)); return result; } /****************************************************************************** * * * Paramètres : binary = élément chargé à manipuler. * * human = description humaine attendue ? * * * * Description : Fournit le contenu représenté de l'élément chargé. * * * * Retour : Contenu représenté. * * * * Remarques : - * * * ******************************************************************************/ static char *g_loaded_binary_get_content_class(const GLoadedBinary *binary, bool human) { char *result; /* Désignation à retourner */ char *part; /* Partie à intégrer */ if (human) { result = g_known_format_get_description(G_KNOWN_FORMAT(binary->format)); result = stradd(result, ", "); part = g_arch_processor_get_desc(binary->proc); result = stradd(result, part); free(part); } else { result = g_known_format_get_key(G_KNOWN_FORMAT(binary->format)); result = stradd(result, "-"); part = g_arch_processor_get_key(binary->proc); result = stradd(result, part); free(part); } return result; } /****************************************************************************** * * * Paramètres : binary = élément chargé dont l'analyse est lancée. * * connect = organise le lancement des connexions aux serveurs. * * cache = précise si la préparation d'un rendu est demandée. * * gid = groupe de travail dédié. * * status = barre de statut à tenir informée. * * * * Description : Assure le désassemblage en différé. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_loaded_binary_analyze(GLoadedBinary *binary, bool connect, bool cache, wgroup_id_t gid, GtkStatusStack *status) { bool result; /* Bilan à retourner */ GBinFormat *format; /* Format lié au binaire */ char *desc; /* Description humaine associée*/ bool has_virt; /* Présence de virtuel ? */ GProcContext *context; /* Contexte de suivi dédié */ GWidthTracker *tracker; /* Gestionnaire de largeur */ /* Interprétation du format associé */ format = G_BIN_FORMAT(binary->format); desc = g_known_format_get_description(G_KNOWN_FORMAT(format)); assert(desc != NULL); log_variadic_message(LMT_INFO, _("Selected format: %s"), desc); free(desc); result = g_known_format_analyze(G_KNOWN_FORMAT(format), gid, status); if (!result) goto glba_exit; /* Interprétation de l'architecture associée */ desc = g_arch_processor_get_desc(binary->proc); assert(desc != NULL); log_variadic_message(LMT_INFO, _("Detected architecture: %s"), desc); free(desc); g_signal_connect(binary->proc, "changed", G_CALLBACK(on_binary_processor_changed), binary); has_virt = g_arch_processor_has_virtual_space(binary->proc); g_display_options_set(binary->options[BVW_HEX], HLC_PHYSICAL, false); g_display_options_set(binary->options[BVW_BLOCK], DLC_VIRTUAL, has_virt); g_display_options_set(binary->options[BVW_GRAPH], DLC_VIRTUAL, has_virt); /* Phase de désassemblage pur */ if (connect) g_loaded_binary_connect_internal(binary); disassemble_binary(binary, gid, status, &context); g_known_format_complete_analysis(G_KNOWN_FORMAT(format), gid, status); if (cache) { output_disassembly(binary, context, status, &binary->disass_cache); tracker = g_buffer_cache_get_width_tracker(binary->disass_cache); g_width_tracker_build_initial_cache(tracker, gid, status); g_object_unref(G_OBJECT(tracker)); } g_object_unref(G_OBJECT(context)); glba_exit: return result; } /****************************************************************************** * * * Paramètres : proc = processeur dont l'ensemble des instructions a varié.* * instr = instruction à l'origine de la procédure. * * added = précise s'il s'agit d'un ajout ou d'un retrait. * * binary = élément chargé à consulter. * * * * Description : Prend note d'une variation des instructions désassemblées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_binary_processor_changed(GArchProcessor *proc, GArchInstruction *instr, gboolean added, GLoadedBinary *binary) { const mrange_t *range; /* Emplacement de l'instruction*/ BufferLineFlags flags; /* Propriétés pour la ligne */ GBinSymbol *symbol; /* Symbole présent à l'adresse */ SymbolType stype; /* Type de symbole rencontré */ instr_iter_t *iter; /* Boucle de parcours */ GArchInstruction *next; /* Instruction suivante */ GLineCursor *cursor; /* Emplacement dans un tampon */ size_t index; /* Indice de ligne à traiter */ if (binary->disass_cache != NULL) { g_buffer_cache_wlock(binary->disass_cache); range = g_arch_instruction_get_range(instr); if (added) { flags = BLF_NONE; if (g_binary_format_find_symbol_at(G_BIN_FORMAT(binary->format), get_mrange_addr(range), &symbol)) { /** * Pour le choix des fanions, se référer au code similaire de * la fonction print_disassembled_instructions(). */ stype = g_binary_symbol_get_stype(symbol); if (stype == STP_ENTRY_POINT) flags |= BLF_ENTRYPOINT; if (stype != STP_DYN_STRING) flags |= BLF_WIDTH_MANAGER; g_object_unref(G_OBJECT(symbol)); } iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(range)); next = get_instruction_iterator_next(iter); delete_instruction_iterator(iter); if (next == NULL) g_buffer_cache_append(binary->disass_cache, G_LINE_GENERATOR(instr), flags); else { range = g_arch_instruction_get_range(next); cursor = g_binary_cursor_new(); g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(range)); index = g_buffer_cache_find_index_by_cursor(binary->disass_cache, cursor, true); g_object_unref(G_OBJECT(cursor)); g_object_unref(G_OBJECT(next)); g_buffer_cache_insert_at(binary->disass_cache, index, G_LINE_GENERATOR(instr), flags, true, false); } } else { cursor = g_binary_cursor_new(); g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(range)); index = g_buffer_cache_find_index_by_cursor(binary->disass_cache, cursor, true); g_object_unref(G_OBJECT(cursor)); g_buffer_cache_delete_at(binary->disass_cache, index); } g_buffer_cache_wunlock(binary->disass_cache); } } /****************************************************************************** * * * Paramètres : binary = élément chargé à consulter. * * full = précise s'il s'agit d'une version longue ou non. * * * * Description : Fournit le désignation associée à l'élément chargé. * * * * Retour : Description courante. * * * * Remarques : - * * * ******************************************************************************/ static char *g_loaded_binary_describe(const GLoadedBinary *binary, bool full) { char *result; /* Description à retourner */ GBinContent *content; /* Contenu binaire mannipulé */ content = g_known_format_get_content(G_KNOWN_FORMAT(binary->format)); result = g_binary_content_describe(content, full); g_object_unref(G_OBJECT(content)); return result; } /****************************************************************************** * * * Paramètres : binary = contenu chargé à consulter. * * * * Description : Détermine le nombre de vues disponibles pour un contenu. * * * * Retour : Quantité strictement positive. * * * * Remarques : - * * * ******************************************************************************/ static unsigned int g_loaded_binary_count_views(const GLoadedBinary *binary) { unsigned int result; /* Quantité de vues à renvoyer */ result = BVW_COUNT; return result; } /****************************************************************************** * * * Paramètres : binary = contenu chargé à consulter. * * index = indice de la vue ciblée. * * * * Description : Fournit le nom d'une vue donnée d'un contenu chargé. * * * * Retour : Désignation humainement lisible. * * * * Remarques : - * * * ******************************************************************************/ static char *g_loaded_binary_get_view_name(const GLoadedBinary *binary, unsigned int index) { char *result; /* Désignation à retourner */ switch (index) { case BVW_HEX: result = strdup(_("Hex view")); break; case BVW_BLOCK: result = strdup(_("Text view")); break; case BVW_GRAPH: result = strdup(_("Graph view")); break; default: assert(false); result = NULL; break; } return result; } /****************************************************************************** * * * Paramètres : binary = contenu chargé à consulter. * * index = indice de la vue ciblée. * * * * Description : Met en place la vue initiale pour un contenu binaire. * * * * Retour : Composant graphique nouveau. * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *g_loaded_binary_build_default_view(GLoadedBinary *binary) { GtkWidget *result; /* Support à retourner */ result = g_loaded_binary_build_view(binary, BVW_BLOCK); return result; } /****************************************************************************** * * * Paramètres : binary = contenu chargé à consulter. * * index = indice de la vue ciblée. * * * * Description : Met en place la vue demandée pour un contenu binaire. * * * * Retour : Composant graphique nouveau. * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *g_loaded_binary_build_view(GLoadedBinary *binary, unsigned int index) { GtkWidget *result; /* Support à retourner */ GBinContent *content; /* Contenu à représenter */ GtkWidget *display; /* Composant d'affichage */ GBufferCache *cache; /* Tampon par défaut */ GBufferView *view; /* Vue sur ce même tampon */ switch (index) { case BVW_HEX: content = g_known_format_get_content(G_KNOWN_FORMAT(binary->format)); display = gtk_hex_display_new(content); g_object_unref(G_OBJECT(content)); break; case BVW_BLOCK: cache = g_loaded_binary_get_disassembly_cache(binary); view = g_buffer_view_new(cache, NULL); display = gtk_block_display_new(view); break; case BVW_GRAPH: display = gtk_graph_display_new(); break; default: assert(false); display = NULL; break; } gtk_widget_show(display); g_loaded_panel_set_content(G_LOADED_PANEL(display), G_LOADED_CONTENT(binary)); result = qck_create_scrolled_window(NULL, NULL); gtk_container_add(GTK_CONTAINER(result), display); return result; } /****************************************************************************** * * * Paramètres : binary = contenu chargé à consulter. * * index = composant graphique en place. * * * * Description : Retrouve l'indice correspondant à la vue donnée d'un contenu.* * * * Retour : Indice de la vue représentée, ou -1 en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ static unsigned int g_loaded_binary_get_view_index(GLoadedBinary *binary, GtkWidget *view) { unsigned int result; /* Indice à retourner */ if (GTK_IS_HEX_DISPLAY(view)) result = BVW_HEX; else if (GTK_IS_BLOCK_DISPLAY(view)) result = BVW_BLOCK; else if (GTK_IS_GRAPH_DISPLAY(view)) result = BVW_GRAPH; else { assert(false); result = -1; } return result; } /****************************************************************************** * * * Paramètres : binary = contenu chargé à consulter. * * index = composant graphique à cibler. * * * * Description : Fournit toutes les options d'affichage pour un contenu. * * * * Retour : Tableau de paramètres en accès libre. * * * * Remarques : - * * * ******************************************************************************/ static GDisplayOptions *g_loaded_binary_get_display_options(const GLoadedBinary *binary, unsigned int index) { GDisplayOptions *result; /* Instance à renvoyer */ if (index < BVW_COUNT) result = binary->options[index]; else result = NULL; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; }