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