/* OpenIDA - Outil d'analyse de fichiers binaires
* format.c - support des différents formats binaires
*
* Copyright (C) 2009-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 "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 "../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 = 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;
}
/******************************************************************************
* *
* 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 à 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. *
* routine = routine à traiter. *
* *
* Description : Procède à la décompilation basique d'une routine donnée. *
* *
* Retour : Instructions créées et enregistrées, ou NULL si erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
GDecInstruction *g_binary_format_decompile_routine(const GBinFormat *format, GBinRoutine *routine)
{
GDecInstruction *result; /* Instructions décompilées */
GArchInstruction *instr; /* Instructions natives */
vmpa_t max; /* Première adresse à écarter */
GDecContext *ctx; /* Contexte de décompilation */
GArchInstruction *iter; /* Boucle de parcours */
GDecInstruction *dinstr; /* Nouvelle décompilation */
result = NULL;
instr = g_binary_routine_get_instructions(routine);
max = g_binary_routine_get_address(routine)
+ g_binary_routine_get_size(routine);
printf("max :: 0x%08llx\n", max);
//max = 0x00000a98ll; /* FIXME !!!! */
ctx = g_dec_context_new();
g_object_set_data(G_OBJECT(ctx), "format", format);
g_dec_context_set_max_address(ctx, max);
for (iter = instr;
iter != NULL;
iter = g_arch_instruction_get_next_iter(instr, iter, max))
{
printf("DECOMP isntr :: %p\n", iter);
dinstr = g_arch_instruction_decompile(iter, ctx);
if (dinstr == NULL) continue;
printf(" -> done :: %p\n", dinstr);
if (result == NULL) result = g_expr_block_new(dinstr);
else g_expr_block_add_item(G_EXPR_BLOCK(result), dinstr);
}
g_binary_routine_set_decomp_instructions(routine, result);
return result;
}
/******************************************************************************
* *
* 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)
{
printf("...\n");
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] *
* type = type du symbole trouvé. [OUT] *
* address = adresse à cibler, puis décallage final. [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 char **label, SymbolType *type, 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->symbols_count && !result; i++)
{
addr = g_binary_symbol_get_address(format->symbols[i]);
size = g_binary_symbol_get_size(format->symbols[i]);
if (addr <= *address && *address < (addr + size))
{
*label = g_binary_symbol_to_string(format->symbols[i]);
*type = g_binary_symbol_get_target_type(format->symbols[i]);
*address -= addr;
if (*type == STP_STRING)
*label += *address;
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, char *filename, bin_t **content, off_t *length)
{
GBinFormat *result; /* Adresse à retourner */
GPluginModule **pglist; /* Liste de greffons */
size_t pgcount; /* Taille de cette liste */
size_t i; /* Boucle de parcours */
result = NULL;
printf("analysing... %s\n", filename);
pglist = get_all_plugins_for_action(PGA_FORMAT_MATCHER, &pgcount);
if (pgcount > 0)
{
lnf_rescan:
for (i = 0; i < pgcount; i++)
switch (g_plugin_module_is_matching(pglist[i], &filename, content, length))
{
case MFA_MATCHED:
/* FIXME */
break;
case MFA_RELOAD:
//goto lnf_rescan;
break;
default:
break;
}
free(pglist);
}
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);
}
printf("FINAL FORMAT :: %p\n", result);
//exit(0);
return result;
}