/* Chrysalide - Outil d'analyse de fichiers binaires
* binary.c - traitement des flots de code binaire
*
* Copyright (C) 2009-2017 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 "db/client.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/global.h"
#include "../core/logs.h"
#include "../core/params.h"
#include "../core/processors.h"
//#include "../glibext/chrysamarshal.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"
/* ------------------------ ENCADREMENTS D'UN BINAIRE CHARGE ------------------------ */
/* Description de fichier binaire (instance) */
struct _GLoadedBinary
{
GObject parent; /* A laisser en premier */
char *username; /* Identifiant de l'utilisateur*/
bool username_changed; /* Mémorise les changements */
bool use_remote; /* Enregistrements distants ? */
char *remote_host; /* Nom du serveur distant */
unsigned short remote_port; /* Port du serveur distant */
GDbClient *local; /* Enregistrements locaux */
GDbClient *remote; /* Enregistrements distants */
DBStorage storages[DBF_COUNT]; /* Lieux d'enregistrement */
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 */
};
/* Description de fichier binaire (classe) */
struct _GLoadedBinaryClass
{
GObjectClass 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 *);
/* Procède à l'initialisation de l'interface de contenu chargé. */
static void g_loaded_binary_interface_init(GLoadedContentInterface *);
/* 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 -------------------------- */
/* ---------------------- 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(const GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *);
/* Fournit le contenu représenté de l'élément chargé. */
static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *);
/* Fournit le contenu représenté de l'élément chargé. */
static const char *g_loaded_binary_get_format_name(const GLoadedBinary *);
/* Assure le désassemblage en différé. */
static bool g_loaded_binary_analyze(GLoadedBinary *, 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 const 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 const char *g_loaded_binary_get_view_name(const GLoadedBinary *, unsigned int);
/* 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_WITH_CODE(GLoadedBinary, g_loaded_binary, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_LOADED_CONTENT, g_loaded_binary_interface_init));
/******************************************************************************
* *
* 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;
}
/******************************************************************************
* *
* 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->use_remote = false;
binary->remote_host = strdup("localhost");
binary->remote_port = 1337;
binary->storages[DBF_BOOKMARKS] = DBS_ALL_LOCAL;
binary->storages[DBF_COMMENTS] = DBS_ALL_LOCAL;
binary->storages[DBF_MOVES] = DBS_ALL_LOCAL;
binary->storages[DBF_DISPLAY_SWITCHERS] = DBS_ALL_LOCAL;
binary->collections = create_collections_list();
attach_binary_to_collections(binary->collections, binary);
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);
}
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
* Description : Procède à l'initialisation de l'interface de contenu chargé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_loaded_binary_interface_init(GLoadedContentInterface *iface)
{
iface->restore = (restore_content_fc)g_loaded_binary_restore;
iface->save = (save_content_fc)g_loaded_binary_save;
iface->get_content = (get_content_fc)g_loaded_binary_get_content;
iface->get_format_name = (get_format_name_fc)g_loaded_binary_get_format_name;
iface->analyze = (analyze_loaded_fc)g_loaded_binary_analyze;
iface->describe = (describe_loaded_fc)g_loaded_binary_describe;
iface->count_views = (count_loaded_views_fc)g_loaded_binary_count_views;
iface->get_view_name = (get_loaded_view_name_fc)g_loaded_binary_get_view_name;
iface->build_view = (build_loaded_view_fc)g_loaded_binary_build_view;
iface->get_view_index = (get_loaded_view_index_fc)g_loaded_binary_get_view_index;
iface->get_options = (get_loaded_options_fc)g_loaded_binary_get_display_options;
}
/******************************************************************************
* *
* 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->local);
g_clear_object(&binary->remote);
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_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);
free(binary->remote_host);
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 */
result = g_object_new(G_TYPE_LOADED_BINARY, NULL);
result->format = format;
return G_LOADED_CONTENT(result);
}
/******************************************************************************
* *
* 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)
{
const char *result; /* Description à retourner */
GBinContent *content; /* Contenu binaire mannipulé */
content = g_binary_format_get_content(G_BIN_FORMAT(binary->format));
result = g_binary_content_describe(content, full);
g_object_unref(G_OBJECT(content));
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, 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 */
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");
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);
/* 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, "host");
if (value == NULL) goto glbls_features;
g_loaded_binary_set_remote_server(binary, value, port);
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_BOOKMARKS:
access = stradd(access, "Bookmarks");
break;
case DBF_COMMENTS:
access = stradd(access, "Comments");
break;
case DBF_MOVES:
access = stradd(access, "Moves");
break;
case DBF_DISPLAY_SWITCHERS:
access = stradd(access, "Segments");
break;
default:
/* Pour GCC */
assert(false);
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);
}
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 */
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");
result &= add_string_attribute_to_node(xdoc, context, storage_path, "remote",
binary->use_remote ? "true" : "false");
/* 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);
free(access);
/* Fonctionnalités */
for (i = 0; i < DBF_COUNT; i++)
{
access = strdup(storage_path);
access = stradd(access, "/Features/");
switch (i)
{
case DBF_BOOKMARKS:
access = stradd(access, "Bookmarks");
break;
case DBF_COMMENTS:
access = stradd(access, "Comments");
break;
case DBF_MOVES:
access = stradd(access, "Moves");
break;
case DBF_DISPLAY_SWITCHERS:
access = stradd(access, "Segments");
break;
default:
/* Pour GCC */
assert(false);
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. *
* *
* 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;
if (use)
/* TODO : reload conn ! */;
else
/* TODO : stop conn ! */;
}
/******************************************************************************
* *
* 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, unsigned short *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, unsigned short port)
{
free(binary->remote_host);
binary->remote_host = strdup(host);
binary->remote_port = port;
}
/******************************************************************************
* *
* 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 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 */
const char *tmp; /* Stockage temporaire */
char *author; /* Identification à diffuser */
char *priv; /* Chemin de la clef privée */
GBinContent *content; /* Contenu bianire manipulé */
const gchar *checksum; /* Identifiant de binaire */
char *host; /* Nom du serveur à contacter */
int port; /* Numéro du port associé */
result = false;
/* Utilisateur représenté */
if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &tmp))
goto glbcl_exit;
author = strdup(tmp);
/* Chemin vers la clef privée */
priv = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.priv");
/* Détermination de l'identifiant */
content = g_binary_format_get_content(G_BIN_FORMAT(binary->format));
checksum = g_binary_content_get_checksum(content);
g_object_unref(G_OBJECT(content));
/* Tentative de connexion */
binary->local = g_db_client_new(author, priv,
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))
/* ... */;
result = g_db_client_start_internal(binary->local);
glbcl_exit:
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 */
const char *tmp; /* Stockage temporaire */
char *author; /* Identification à diffuser */
char *priv; /* Chemin de la clef privée */
GBinContent *content; /* Contenu bianire manipulé */
const gchar *checksum; /* Identifiant de binaire */
char *host; /* Nom du serveur à contacter */
int port; /* Numéro du port associé */
result = false;
/* Utilisateur représenté */
if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &tmp))
goto glbcl_exit;
author = strdup(tmp);
/* Chemin vers la clef privée */
priv = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.priv");
/* Détermination de l'identifiant */
content = g_binary_format_get_content(G_BIN_FORMAT(binary->format));
checksum = g_binary_content_get_checksum(content);
g_object_unref(G_OBJECT(content));
/* Tentative de connexion */
binary->local = g_db_client_new(author, priv,
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))
/* ... */;
result = g_db_client_start_remote(binary->local, host, port);
glbcl_exit:
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 le client assurant la liaison avec un serveur. *
* *
* Retour : Client connecté ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *binary)
{
GDbClient *result; /* Instance à retourner */
result = binary->local;
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_all_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);
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. *
* 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, GDbItem *item, bool lock)
{
bool result; /* Bilan à faire remonter */
DBFeatures feature; /* Domaine de fonctionnalité */
GDbCollection *collec; /* Collection visée au final */
DBStorage storage; /* Forme d'enregistrement */
GDbClient *client; /* Liaison à utiliser */
packed_buffer out_pbuf; /* Tampon d'émission */
int fd; /* Identifiant du canal de com.*/
feature = g_db_item_get_feature(item);
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))
result = _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;
init_packed_buffer(&out_pbuf);
fd = g_db_client_get_fd(client);
result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item);
g_db_client_put_fd(client);
if (result)
result = send_packed_buffer(&out_pbuf, fd);
exit_packed_buffer(&out_pbuf);
}
g_object_unref(G_OBJECT(collec));
g_object_unref(G_OBJECT(item));
return result;
}
/******************************************************************************
* *
* Paramètres : binary = élément binaire à consulter. *
* feature = fonctionnalité visée par la requête. *
* item = élémnent à retirer d'un serveur de collection. *
* lock = indique si le verrou d'écriture doit être posé. *
* *
* Description : Demande la suppression de modification dans une collection. *
* *
* Retour : Bilan partiel de l'opération demandée. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _g_loaded_binary_remove_from_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 */
packed_buffer out_pbuf; /* Tampon d'émission */
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))
result = _g_db_collection_remove_item(collec, item, lock, true);
/* 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;
init_packed_buffer(&out_pbuf);
fd = g_db_client_get_fd(client);
result = g_db_collection_pack(collec, &out_pbuf, DBA_REM_ITEM, item);
g_db_client_put_fd(client);
if (result)
result = send_packed_buffer(&out_pbuf, fd);
exit_packed_buffer(&out_pbuf);
}
g_object_unref(G_OBJECT(collec));
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;
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_disassembled_cache(const GLoadedBinary *binary)
{
GBufferCache *result; /* Instance à retourner */
result = binary->disass_cache;
if (result != NULL)
g_object_ref(G_OBJECT(result));
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);
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(const GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path)
{
bool result; /* Bilan à faire remonter */
/* Mise en cache des instructions */
result = g_loaded_binary_save_cache(binary);
/* Elément divers associés au binaire */
if (result)
result = g_loaded_binary_save_storage(binary, xdoc, context, path);
/* Sauvegarde côté serveur */
if (result)
g_db_client_save(binary->local);
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_binary_format_get_content(G_BIN_FORMAT(binary->format));
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 const char *g_loaded_binary_get_format_name(const GLoadedBinary *binary)
{
const char *result; /* Désignation à retourner */
result = g_binary_format_get_name(G_BIN_FORMAT(binary->format));
return result;
}
/******************************************************************************
* *
* Paramètres : binary = élément chargé dont l'analyse est lancé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, wgroup_id_t gid, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
GBinFormat *format; /* Format lié au binaire */
const char *desc; /* Description humaine associée*/
const char *arch; /* Architecture d'exécution */
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_binary_format_get_description(format);
if (desc == NULL)
log_simple_message(LMT_WARNING, _("Unnamed format"));
else
log_variadic_message(LMT_INFO, _("Selected format: %s"), desc);
result = g_binary_format_analyze(format, gid, status);
if (!result) goto glba_exit;
/* Architecture visée */
arch = g_exe_format_get_target_machine(binary->format);
desc = get_arch_processor_name(arch);
if (desc == NULL)
{
log_simple_message(LMT_INFO, _("Unknown architecture"));
goto glba_exit;
}
else
log_variadic_message(LMT_INFO, _("Detected architecture: %s"), desc);
binary->proc = get_arch_processor_for_type(arch);
if (binary->proc == NULL)
{
log_simple_message(LMT_ERROR, _("Unable to load the required processor"));
goto glba_exit;
}
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_BLOCK], BLC_VIRTUAL, has_virt);
g_display_options_set(binary->options[BVW_GRAPH], BLC_VIRTUAL, has_virt);
/* Phase de désassemblage pur */
if (!is_batch_mode())
g_loaded_binary_connect_internal(binary);
disassemble_binary(binary, gid, status, &context);
g_binary_format_complete_analysis(format, gid, status);
if (!is_batch_mode())
{
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));
}
result = true;
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)
{
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_target_type(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);
}
}
}
/******************************************************************************
* *
* 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 const char *g_loaded_binary_describe(const GLoadedBinary *binary, bool full)
{
const char *result; /* Description à retourner */
GBinContent *content; /* Contenu binaire mannipulé */
content = g_binary_format_get_content(G_BIN_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)
{
return BVW_COUNT;
}
/******************************************************************************
* *
* 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 const char *g_loaded_binary_get_view_name(const GLoadedBinary *binary, unsigned int index)
{
const char *result; /* Désignation à retourner */
switch (index)
{
case BVW_BLOCK:
result = _("Text view");
break;
case BVW_GRAPH:
result = _("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 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 */
GBufferCache *cache; /* Tampon par défaut */
GBufferView *view; /* Vue sur ce même tampon */
GtkWidget *display; /* Composant d'affichage */
switch (index)
{
case BVW_BLOCK:
cache = g_loaded_binary_get_disassembled_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_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;
}