/* Chrysalide - Outil d'analyse de fichiers binaires * binary.c - traitement des flots de code binaire * * Copyright (C) 2008-2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "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" #include "../common/cpp.h" #include "../core/collections.h" #include "../core/params.h" #include "../glibext/chrysamarshal.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 *); /* Acquitte la fin d'un désasemblage différé et complet. */ static void ack_completed_disassembly(GDelayedDisassembly *, GLoadedBinary *); /* ------------------------- INFORMATIONS D'ENREGISTREMENTS ------------------------- */ /* Charge en mémoire les formes d'enregistrement du XML. */ static bool g_loaded_binary_load_storage(GLoadedBinary *, xmlXPathContextPtr, const char *); /* Ecrit les formes d'enregistrement du binaire dans du XML. */ static bool g_loaded_binary_save_storage(const GLoadedBinary *, xmlDocPtr, xmlXPathContextPtr, const char *); /* -------------------------- MANIPULATION DES COLLECTIONS -------------------------- */ /* 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); g_signal_new("display-changed", G_TYPE_LOADED_BINARY, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GLoadedBinaryClass, display_changed), NULL, NULL, g_cclosure_user_marshal_VOID__ENUM_ENUM, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); } /****************************************************************************** * * * Paramètres : binary = instance à initialiser. * * * * Description : Initialise une description de fichier binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_loaded_binary_init(GLoadedBinary *binary) { binary->username = strdup("default"); binary->remote_host = strdup("localhost"); binary->remote_port = 9999; binary->use_remote_server = false; binary->storages[DBF_COMMENTS] = DBS_ALL_LOCAL; binary->storages[DBF_DISPLAY_SWITCHERS] = DBS_ALL_LOCAL; binary->storages[DBF_BOOKMARKS] = DBS_ALL_LOCAL; binary->collections = create_collections_list(); attach_binary_to_collections(binary->collections, binary); binary->col_display[BVW_BLOCK][BLC_PHYSICAL] = true; binary->col_display[BVW_BLOCK][BLC_VIRTUAL] = true; binary->col_display[BVW_BLOCK][BLC_BINARY] = true; binary->col_display[BVW_GRAPH][BLC_PHYSICAL] = false; binary->col_display[BVW_GRAPH][BLC_VIRTUAL] = false; binary->col_display[BVW_GRAPH][BLC_BINARY] = false; binary->col_display[BVW_SOURCE][BLC_PHYSICAL] = false; binary->col_display[BVW_SOURCE][BLC_VIRTUAL] = false; binary->col_display[BVW_SOURCE][BLC_BINARY] = 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) { free(binary->username); /* 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; /* Type de binaire à charger */ result = NULL; type = get_node_prop_value(context, path, "type"); if (strcmp(type, "file") == 0) result = g_file_binary_new_from_xml(context, path); free(type); if (result == NULL) return NULL; /* --------- %< --------- TODO : à bouger pour + de générique --------- %< --------- */ // -> init() //result->collections = create_collections_list(); if (!g_loaded_binary_load_storage(result, context, path)) goto glbnfx_error; /* --------- %< --------- TODO : à bouger pur + de générique --------- %< --------- */ 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); result = g_loaded_binary_save_storage(binary, xdoc, context, path); //// g_db_client_save(binary->local); return 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, xmlXPathContextPtr context, const char *path) { bool result; /* Bilan à faire remonter */ char *storage_path; /* Partie "Enregistrement" */ char *access; /* Chemin d'accès à un élément */ char *value; /* Valeur lue à partie du XML */ unsigned short port; /* Port de communication */ bool use; /* Usage d'un serveur distant */ DBFeatures i; /* Boucle de parcours */ result = true; storage_path = strdup(path); storage_path = stradd(storage_path, "/Storage"); /* Nom d'utilisateur */ access = strdup(storage_path); access = stradd(access, "/Username"); value = get_node_text_value(context, access); if (value != NULL) { g_loaded_binary_set_username(binary, value); free(value); } free(access); /* 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 = atoi(value); free(value); value = get_node_prop_value(context, access, "use"); if (value == NULL) goto glbls_features; use = (strcmp(value, "true") == 0); free(value); value = get_node_prop_value(context, access, "host"); if (value == NULL) goto glbls_features; g_loaded_binary_set_remote_server(binary, value, port, use); free(value); glbls_features: free(access); /* Fonctionnalités */ for (i = 0; i < DBF_COUNT; i++) { access = strdup(storage_path); access = stradd(access, "/Features/"); switch (i) { case DBF_COMMENTS: access = stradd(access, "Comments"); break; case DBF_DISPLAY_SWITCHERS: access = stradd(access, "Segments"); break; case DBF_BOOKMARKS: access = stradd(access, "Bookmarks"); break; case DBF_COUNT: /* Pour GCC */ break; } value = get_node_text_value(context, access); if (value != NULL) { if (atoi(value) <= DBS_MAX) g_loaded_binary_set_storage(binary, i, atoi(value)); } free(access); } 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, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path) { bool result; /* Bilan à faire remonter */ char *storage_path; /* Partie "Enregistrement" */ char *access; /* Chemin d'accès à un élément */ char port_str[sizeof(XSTR(USHRT_MAX)) + 1]; /* Version chaînée */ DBFeatures i; /* Boucle de parcours */ result = true; storage_path = strdup(path); storage_path = stradd(storage_path, "/Storage"); /* Nom d'utilisateur */ access = strdup(storage_path); access = stradd(access, "/Username"); result &= add_content_to_node(xdoc, context, access, binary->username); free(access); /* Serveur distant */ access = strdup(storage_path); access = stradd(access, "/RemoteServer"); result &= add_string_attribute_to_node(xdoc, context, access, "host", binary->remote_host); sprintf(port_str, "%hu", binary->remote_port); result &= add_string_attribute_to_node(xdoc, context, access, "port", port_str); result &= add_string_attribute_to_node(xdoc, context, access, "use", binary->use_remote_server ? "true" : "false"); free(access); /* Fonctionnalités */ for (i = 0; i < DBF_COUNT; i++) { access = strdup(storage_path); access = stradd(access, "/Features/"); switch (i) { case DBF_COMMENTS: access = stradd(access, "Comments"); break; case DBF_DISPLAY_SWITCHERS: access = stradd(access, "Segments"); break; case DBF_BOOKMARKS: access = stradd(access, "Bookmarks"); break; case DBF_COUNT: /* Pour GCC */ break; } result &= add_uint_content_to_node(xdoc, context, access, binary->storages[i]); free(access); } free(storage_path); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * * * Description : Identifie l'utilisateur analysant le binaire courant. * * * * Retour : Nom de l'utilisateur manipulant le binaire. * * * * Remarques : - * * * ******************************************************************************/ const char *g_loaded_binary_get_username(const GLoadedBinary *binary) { return binary->username; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * username = nom de l'utilisateur manipulant le binaire. * * * * Description : Définit l'utilisateur analysant le binaire courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_set_username(GLoadedBinary *binary, const char *username) { bool changed; /* Note les changements */ changed = (strcmp(binary->username, username) != 0); free(binary->username); binary->username = strdup(username); binary->username_changed = changed; } /****************************************************************************** * * * 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 : Statut de l'utilisation du serveur distant. * * * * Remarques : - * * * ******************************************************************************/ bool g_loaded_binary_get_remote_server(const GLoadedBinary *binary, const char **host, unsigned short *port) { *host = binary->remote_host; *port = binary->remote_port; return binary->use_remote_server; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * host = nom du serveur distant à contacter. * * port = port de communication avec le serveur distant. * * use = statut de l'utilisation du 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, unsigned short port, bool use) { free(binary->remote_host); binary->remote_host = strdup(host); binary->remote_port = port; binary->use_remote_server = use; if (use) /* TODO : reload conn ! */; else /* TODO : stop conn ! */; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * feature = fonctionnalité visée par la requête. * * * * Description : Indique la forme d'enregistrement d'une fonctionnalité. * * * * Retour : Type d'enregistrement sélectionné. * * * * Remarques : - * * * ******************************************************************************/ DBStorage g_loaded_binary_get_storage(const GLoadedBinary *binary, DBFeatures feature) { return binary->storages[feature]; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * feature = fonctionnalité visée par la requête. * * storage = type d'enregistrement sélectionné. * * * * Description : Définit la forme d'enregistrement d'une fonctionnalité. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_set_storage(GLoadedBinary *binary, DBFeatures feature, DBStorage storage) { binary->storages[feature] = storage; } /****************************************************************************** * * * Paramètres : binary = élément binaire à manipuler. * * * * Description : Etablit une connexion à un serveur en tant que client. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_loaded_binary_connect(GLoadedBinary *binary) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu bianire manipulé */ const gchar *checksum; /* Identifiant de binaire */ char *host; /* Nom du serveur à contacter */ int port; /* Numéro du port associé */ char *author; /* Identification à diffuser */ /* Détermination de l'identifiant */ content = g_binary_format_get_content(G_BIN_FORMAT(binary->format)); checksum = g_binary_content_get_cheksum(content); g_object_unref(G_OBJECT(content)); binary->local = g_db_client_new(g_loaded_binary_get_name(binary, false), checksum, binary->collections); if (!g_generic_config_get_value(get_main_configuration(), MPK_LOCAL_HOST, &host)) /* ... */; if (!g_generic_config_get_value(get_main_configuration(), MPK_LOCAL_PORT, &port)) /* ... */; if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &author)) /* ... */; result = g_db_client_start(binary->local, host, port, author); printf("DB status :: %d\n", result); return result; } /* ---------------------------------------------------------------------------------- */ /* MANIPULATION DES COLLECTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * 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(GLoadedBinary *binary, DBFeatures feature) { GDbCollection *result; /* Collection à retourner */ /* TODO : lock */ result = find_collection_in_list(binary->collections, feature); if (result != NULL) g_object_ref(G_OBJECT(result)); /* TODO : unlock */ return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * feature = fonctionnalité visée par la requête. * * item = élémnent à pousser vers un serveur de collection. * * lock = indique si le verrou d'écriture doit être posé. * * * * 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, DBFeatures feature, GDbItem *item, bool lock) { bool result; /* Bilan à faire remonter */ GDbCollection *collec; /* Collection visée au final */ DBStorage storage; /* Forme d'enregistrement */ GDbClient *client; /* Liaison à utiliser */ int fd; /* Identifiant du canal de com.*/ collec = g_loaded_binary_find_collection(binary, feature); if (collec == NULL) return false; /* S'il n'y a pas besoin de sauvegarde... */ if (g_db_item_is_volatile(item)) _g_db_collection_add_item(collec, item, lock); /* Sinon on envoie par le réseau ! */ else { storage = g_loaded_binary_get_storage(binary, feature); /* TODO : sélection du bon client... */ client = binary->local; fd = g_db_client_get_fd(client); result = g_db_collection_send(collec, fd, DBA_ADD_ITEM, item); g_db_client_put_fd(client); } g_object_unref(G_OBJECT(collec)); g_object_unref(G_OBJECT(item)); return result; } /****************************************************************************** * * * 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) { /* Détermination de l'identifiant */ /* Contacts avec les serveurs */ // Déconnexion... disassemble_binary(binary, &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 nom associé à l'élément binaire. * * * * Retour : Nom de fichier avec chemin absolu. * * * * Remarques : - * * * ******************************************************************************/ const char *g_loaded_binary_get_name(const GLoadedBinary *binary, bool full) { return binary->get_name(binary, full); } /****************************************************************************** * * * 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) { /* TODO : inc ref ! */ return binary->format; } /****************************************************************************** * * * 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; 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 : - * * * ******************************************************************************/ GCodeBuffer *g_loaded_binary_get_disassembled_buffer(const GLoadedBinary *binary) { return binary->disass_buffer; } /****************************************************************************** * * * 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 à mettre à jour. * * view = type de représentation visée. * * col = indice de colonne dont l'affichage est à modifier. * * state = nouvel état de l'affichage. * * * * Description : Définit si une colonne donnée doit apparaître dans le rendu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_loaded_binary_set_column_display(GLoadedBinary *binary, BinaryView view, BufferLineColumn col, bool state) { bool old; /* Ancien état à remplacer */ old = binary->col_display[view][col]; if (state != old) { binary->col_display[view][col] = state; g_signal_emit_by_name(binary, "display-changed", view, col); } } /****************************************************************************** * * * Paramètres : binary = élément binaire à consulter. * * view = type de représentation visée. * * * * Description : Indique quelles colonnes doivent apparaître dans le rendu. * * * * Retour : Consigne d'affichage. [OUT] * * * * Remarques : - * * * ******************************************************************************/ const bool *g_loaded_binary_get_column_display(GLoadedBinary *binary, BinaryView view) { return binary->col_display[view]; } /****************************************************************************** * * * 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)); g_loaded_binary_connect(binary); /* 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"); }