/* Chrysalide - Outil d'analyse de fichiers binaires
* format.c - support des différents formats binaires
*
* Copyright (C) 2009-2013 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* OpenIDA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* OpenIDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "format.h"
#include
#include "format-int.h"
#include "dex/dex.h"
#include "dwarf/dwarf.h"
#include "elf/elf.h"
#include "java/java.h"
#include "pe/pe.h"
#include "../arch/processor.h"
#include "../decomp/expr/block.h"
#include "../gui/panels/log.h"
#include "../plugins/pglist.h"
#ifndef _
# define _(str) str
#endif
/* ------------------------ TRAITEMENT INDIVIDUEL DE FORMATS ------------------------ */
/* Initialise la classe des formats binaires génériques. */
static void g_binary_format_class_init(GBinFormatClass *);
/* Initialise une instance de format binaire générique. */
static void g_binary_format_init(GBinFormat *);
/* ----------------------- MANIPULATION D'ENSEMBLE DE FORMATS ----------------------- */
/* Format d'exécutables enregistré */
typedef struct _registered_format
{
const char *name; /* Désignation du format */
FormatType type; /* Type de format */
format_match_fc match; /* Procédure de reconnaissance */
format_load_fc load; /* Fonction de chargement */
} registered_format;
/* Liste des formats d'exécutables enregistrés */
static registered_format _formats[FID_COUNT];
#define register_format(id, n, t, m, l) \
do \
{ \
_formats[id].name = n; \
_formats[id].type = t; \
_formats[id].match = m; \
_formats[id].load = l; \
} \
while (0)
/* ---------------------------------------------------------------------------------- */
/* TRAITEMENT INDIVIDUEL DE FORMATS */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour un format binaire générique. */
G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des formats binaires génériques. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_format_class_init(GBinFormatClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : format = instance à initialiser. *
* *
* Description : Initialise une instance de format binaire générique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_format_init(GBinFormat *format)
{
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* content = contenu binaire à parcourir. *
* length = taille du contenu fourni. *
* *
* Description : Définit le contenu binaire à analyser. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_format_set_content(GBinFormat *format, const bin_t *content, off_t length)
{
format->content = content;
format->length = length;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* length = taille du contenu à fournir. [OUT] *
* *
* Description : Fournit une référence vers le contenu binaire analysé. *
* *
* Retour : Adresse du tampon contenant le contenu du binaire. *
* *
* Remarques : - *
* *
******************************************************************************/
const bin_t *g_binary_format_get_content(const GBinFormat *format, off_t *length)
{
if (length != NULL) *length = format->length;
return format->content;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* ctx = contexte de désassemblage à préparer. *
* *
* Description : Fournit un contexte initialisé pour un désassemblage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_format_setup_disassembling_context(const GBinFormat *format, GProcContext *ctx)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < format->ep_count; i++)
g_proc_context_push_drop_point(ctx, format->entry_points[i]);
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à compléter. *
* symbol = symbole à ajouter à la liste. *
* *
* Description : Ajoute un symbole à la collection du format binaire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol)
{
format->symbols = (GBinSymbol **)realloc(format->symbols,
++format->symbols_count * sizeof(GBinSymbol *));
format->symbols[format->symbols_count - 1] = symbol;
qsort(format->symbols, format->symbols_count,
sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp);
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* count = taille du tableau créé. [OUT] *
* *
* Description : Fournit la liste de tous les symboles détectés. *
* *
* Retour : Tableau créé ou NULL si aucun symbole trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinSymbol **g_binary_format_get_symbols(const GBinFormat *format, size_t *count)
{
*count = format->symbols_count;
return format->symbols;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* addr = adresse à cibler lors des recherches. *
* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] *
* *
* Description : Recherche le symbole correspondant à une adresse. *
* *
* Retour : true si l'opération a été un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_binary_format_find_symbol_at(const GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
const mrange_t *range; /* Espace mémoire parcouru */
result = false;
for (i = 0; i < format->symbols_count && !result; i++)
{
range = g_binary_symbol_get_range(format->symbols[i]);
if (cmp_vmpa(get_mrange_addr(range), addr) == 0)
{
*symbol = format->symbols[i];
g_object_ref(G_OBJECT(*symbol));
result = true;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* addr = adresse à cibler lors des recherches. *
* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] *
* diff = décallage entre l'adresse et le symbole. [OUT] *
* *
* Description : Recherche le symbole correspondant à une adresse. *
* *
* Retour : true si l'opération a été un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_binary_format_resolve_symbol(const GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol, phys_t *diff)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
const mrange_t *range; /* Espace mémoire parcouru */
result = false;
//for (i = 0; i < format->symbols_count && !result; i++)
for (i = format->symbols_count; i > 0 && !result; i--)
{
range = g_binary_symbol_get_range(format->symbols[i - 1]);
if (mrange_contains_addr(range, addr))
{
*symbol = format->symbols[i - 1];
g_object_ref(G_OBJECT(*symbol));
*diff = compute_vmpa_diff(get_mrange_addr(range), addr);
result = true;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à compléter. *
* routine = routine à ajouter à la liste. *
* *
* Description : Ajoute une routine à la collection du format binaire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_format_add_routine(GBinFormat *format, GBinRoutine *routine)
{
format->routines = (GBinRoutine **)realloc(format->routines,
++format->routines_count * sizeof(GBinRoutine *));
format->routines[format->routines_count - 1] = routine;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* count = taille du tableau créé. [OUT] *
* *
* Description : Fournit le prototype de toutes les routines détectées. *
* *
* Retour : Tableau créé ou NULL si aucun symbole de routine trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinRoutine **g_binary_format_get_routines(const GBinFormat *format, size_t *count)
{
*count = format->routines_count;
return format->routines;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* count = taille de la liste retournée. [OUT] *
* defsrc = fichier de code principal. [OUT] *
* *
* Description : Fournit la liste des fichiers source détectés. *
* *
* Retour : Liste de noms de fichier ou NULL si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
const char * const *g_binary_format_get_source_files(const GBinFormat *format, size_t *count, size_t *defsrc)
{
*count = format->src_count;
*defsrc = format->def_source;
return format->src_files;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* buffer = tampon mis à disposition pour la sortie. *
* filename = nom du fichier source à cibler. *
* *
* Description : Procède à la décompilation complète du format. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_format_decompile(const GBinFormat *format, GCodeBuffer *buffer, const char *filename)
{
GBinRoutine **routines;
size_t count;
size_t i;
GDecInstruction *instr;
if (format->decompile != NULL)
format->decompile(format, buffer, filename);
routines = g_binary_format_get_routines(format, &count);
for (i = 0; i < count; i++)
{
//printf(" -- %s --\n", g_binary_routine_get_name(routines[i]));
//if (strcmp("cryptself", g_binary_routine_get_name(routines[i])) == 0)
{
instr = g_binary_routine_get_decomp_instructions(routines[i]);
if (instr == NULL) continue;
//g_dec_instruction_print(instr, buffer, NULL, g_java_output_new());
}
}
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* label = étiquette du symbole si trouvé. [OUT] *
* address = adresse à cibler, puis décallage final. [OUT] *
* *
* Description : Recherche une position dans une routine selon une adresse. *
* *
* Retour : true si l'opération a été un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_binary_format_resolve_relative_routine(const GBinFormat *format, const char **label, vmpa_t *address)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
vmpa_t addr; /* Adresse de symbole */
off_t size; /* Taille du symole */
result = false;
for (i = 0; i < format->routines_count && !result; i++)
{
addr = g_binary_routine_get_address(format->routines[i]);
size = g_binary_routine_get_size(format->routines[i]);
if (addr <= *address && *address < (addr + size))
{
*label = g_binary_routine_get_long_name(format->routines[i]);
*address -= addr;
result = true;
}
}
return result;
}
/* ---------------------------------------------------------------------------------- */
/* MANIPULATION D'ENSEMBLE DE FORMATS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Procède au chargement des formats binaires reconnus. *
* *
* Retour : true pour indiquer un chargement réussi, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool init_all_formats(void)
{
register_format(FID_DEX, _("Dalvik Executable"), FMT_EXEC, dex_is_matching, g_dex_format_new);
//register_format(FID_DWARF, _("Dwarf"), FMT_DEBUG, dwarf_is_matching, g_dwarf_format_new);
register_format(FID_ELF, _("ELF"), FMT_EXEC, elf_is_matching, g_elf_format_new);
register_format(FID_JAVA, _("Java"), FMT_EXEC, java_is_matching, g_java_format_new);
register_format(FID_PE, _("PE"), FMT_EXEC, pe_is_matching, g_pe_format_new);
return true;
}
/******************************************************************************
* *
* Paramètres : type = type de format recherché. *
* filename = fichier d'origine des données initiales. *
* content = contenu binaire à parcourir. [OUT] *
* length = taille du contenu en question. [OUT] *
* *
* Description : Charge si possible un nouveau format binaire. *
* *
* Retour : Adresse du nouveau gestionnaire de format ou NULL si erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinFormat *load_new_format(FormatType type, const char *filename, bin_t **content, off_t *length)
{
GBinFormat *result; /* Adresse à retourner */
char *tmp; /* Nom de fichier modifiable */
GPluginModule **pglist; /* Liste de greffons */
size_t pgcount; /* Taille de cette liste */
size_t i; /* Boucle de parcours */
result = NULL;
tmp = strdup(filename);
pgcount = 0;
pglist = NULL;//get_all_plugins_for_action(PGA_FORMAT_MATCHER, &pgcount);
if (pgcount > 0)
{
lnf_rescan:
for (i = 0; i < pgcount; i++)
switch (0/*g_plugin_module_is_matching(pglist[i], &tmp, content, length)*/)
{
case MFA_MATCHED:
/* FIXME */
break;
case MFA_RELOAD:
//goto lnf_rescan;
break;
default:
break;
}
free(pglist);
}
if (tmp == NULL)
free(tmp);
for (i = 0; i < FID_COUNT && result == NULL; i++)
if (_formats[i].type == type && _formats[i].match(type, *content, *length))
{
log_variadic_message(LMT_INFO, _("%s is matching..."), _formats[i].name);
result = _formats[i].load(*content, *length);
}
return result;
}