/* 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/columns.h"
#include "../core/logs.h"
#include "../core/params.h"
#include "../core/processors.h"
#include "../format/known.h"
#include "../glibext/gbinarycursor.h"
#ifdef HAVE_GTK_SUPPORT
# include "../glibext/gloadedpanel.h"
# include "../gtkext/easygtk.h"
# include "../gtkext/gtkdisplaypanel.h"
# include "../gtkext/gtkgraphdisplay.h"
#endif
/* ------------------------ 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);
#ifdef HAVE_GTK_SUPPORT
/* 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);
#endif
/* ---------------------------------------------------------------------------------- */
/* 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;
#ifdef HAVE_GTK_SUPPORT
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;
#endif
}
/******************************************************************************
* *
* 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 : Décrit la nature du contenu reconnu pour l'élément chargé. *
* *
* Retour : Classe de contenu associée à l'élément chargé. *
* *
* 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é */
#ifdef HAVE_GTK_SUPPORT
GWidthTracker *tracker; /* Gestionnaire de largeur */
#endif
/* 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);
#ifdef HAVE_GTK_SUPPORT
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));
#endif
}
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;
}
#ifdef HAVE_GTK_SUPPORT
/******************************************************************************
* *
* 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;
}
#endif