/* OpenIDA - Outil d'analyse de fichiers binaires
* class.c - manipulation des classes du format DEX
*
* Copyright (C) 2010-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 "class.h"
#include
#include "dex-int.h"
#include "method.h"
#include "pool.h"
/* Classe issue du code source (instance) */
struct _GDexClass
{
GObject parent; /* A laisser en premier */
class_def_item definition; /* Définition de la classe */
GDexMethod **direct_methods; /* Méthodes propres */
size_t dmethods_count; /* Quantité de ces méthodes */
GDexMethod **virtual_methods; /* Méthodes virtuelles */
size_t vmethods_count; /* Quantité de ces méthodes */
};
/* Classe issue du code source (classe) */
struct _GDexClassClass
{
GObjectClass parent; /* A laisser en premier */
};
/* Procède à l'initialisation d'une classe issue du code source. */
static void g_dex_class_class_init(GDexClassClass *);
/* Procède à l'initialisation d'une classe issue du code source. */
static void g_dex_class_init(GDexClass *);
/* Crée une nouvelle représentation de classe issue de code. */
static GDexClass *g_dex_class_new(const GDexFormat *, off_t);
/* Inscrit les méthodes d'une classe en tant que routines. */
static void g_dex_class_register_method(const GDexClass *, GBinFormat *);
/* Détermine le type d'une classe issue du code source. */
G_DEFINE_TYPE(GDexClass, g_dex_class, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : class = classe de composant GLib à initialiser. *
* *
* Description : Procède à l'initialisation d'une classe issue du code source.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dex_class_class_init(GDexClassClass *class)
{
}
/******************************************************************************
* *
* Paramètres : class = composant GLib à initialiser. *
* *
* Description : Procède à l'initialisation d'une classe issue du code source.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dex_class_init(GDexClass *class)
{
}
/******************************************************************************
* *
* Paramètres : format = représentation interne du format DEX à consulter. *
* offset = tête de lecture des données initiale. *
* *
* Description : Crée une nouvelle représentation de classe issue de code. *
* *
* Retour : Composant GLib créé. *
* *
* Remarques : - *
* *
******************************************************************************/
static GDexClass *g_dex_class_new(const GDexFormat *format, off_t offset)
{
GDexClass *result; /* Composant à retourner */
class_def_item def; /* Définition de la classe */
class_data_item data; /* Contenu de la classe */
uleb128_t index; /* Conservation du dernier id */
uleb128_t i; /* Boucle de parcours */
GDexMethod *method; /* Méthode chargée */
if (!read_dex_class_def_item(format, &offset, &def))
return NULL;
offset = def.class_data_off;
if (!read_dex_class_data_item(format, &offset, &data))
return NULL;
//printf(" Classe :: d meth count == 0x%lld\n", data.direct_methods_size);
//printf(" Classe :: v meth count == 0x%lld\n", data.virtual_methods_size);
result = g_object_new(G_TYPE_DEX_CLASS, NULL);
result->definition = def;
index = 0;
for (i = 0; i < data.direct_methods_size; i++)
{
method = g_dex_method_new(format, &data.direct_methods[i], &index);
if (method != NULL)
{
result->dmethods_count++;
result->direct_methods = (GDexMethod **)realloc(result->direct_methods,
result->dmethods_count * sizeof(GDexMethod *));
result->direct_methods[result->dmethods_count - 1] = method;
}
}
index = 0;
for (i = 0; i < data.virtual_methods_size; i++)
{
method = g_dex_method_new(format, &data.virtual_methods[i], &index);
if (method != NULL)
{
result->vmethods_count++;
result->virtual_methods = (GDexMethod **)realloc(result->virtual_methods,
result->vmethods_count * sizeof(GDexMethod *));
result->virtual_methods[result->vmethods_count - 1] = method;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : class = informations chargées à consulter. *
* format = format binaire à compléter. *
* *
* Description : Inscrit les méthodes d'une classe en tant que routines. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dex_class_register_method(const GDexClass *class, GBinFormat *format)
{
size_t i; /* Boucle de parcours */
GBinRoutine *routine; /* Routine à inscrire */
for (i = 0; i < class->dmethods_count; i++)
{
routine = g_dex_method_get_routine(class->direct_methods[i]);
g_binary_format_add_routine(format, routine);
/*
printf("routine @ 0x%08llx :: '%s'\n",
g_binary_routine_get_address(routine),
g_binary_routine_get_name(routine));
*/
}
for (i = 0; i < class->vmethods_count; i++)
{
routine = g_dex_method_get_routine(class->virtual_methods[i]);
g_binary_format_add_routine(format, routine);
/*
printf("routine @ 0x%08llx :: '%s'\n",
g_binary_routine_get_address(routine),
g_binary_routine_get_name(routine));
*/
}
}
/******************************************************************************
* *
* Paramètres : class = informations chargées à consulter. *
* parts = liste à venir compléter. *
* count = quantité de zones listées. [OUT] *
* *
* Description : Fournit les références aux zones binaires à analyser. *
* *
* Retour : Zones binaires à analyser. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinPart **g_dex_class_get_parts(const GDexClass *class, GBinPart **parts, size_t *count)
{
size_t i; /* Boucle de parcours */
GBinPart *part; /* Partie à intégrer à la liste*/
for (i = 0; i < class->dmethods_count; i++)
{
part = g_dex_method_as_part(class->direct_methods[i]);
parts = (GBinPart **)realloc(parts, ++(*count) * sizeof(GBinPart *));
parts[*count - 1] = part;
}
for (i = 0; i < class->vmethods_count; i++)
{
part = g_dex_method_as_part(class->virtual_methods[i]);
parts = (GBinPart **)realloc(parts, ++(*count) * sizeof(GBinPart *));
parts[*count - 1] = part;
}
return parts;
}
/******************************************************************************
* *
* Paramètres : class = informations chargées à consulter. *
* addr = adresse de la routine à retrouver. *
* *
* Description : Retrouve si possible la méthode associée à une adresse. *
* *
* Retour : Méthde retrouvée ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GDexMethod *g_dex_class_find_method_by_address(const GDexClass *class, vmpa_t addr)
{
GDexMethod *result; /* Trouvaille à retourner */
size_t i; /* Boucle de parcours */
result = NULL;
for (i = 0; i < class->dmethods_count && result == NULL; i++)
if (addr == (vmpa_t)g_dex_method_get_offset(class->direct_methods[i]))
result = class->direct_methods[i];
for (i = 0; i < class->vmethods_count && result == NULL; i++)
if (addr == (vmpa_t)g_dex_method_get_offset(class->virtual_methods[i]))
result = class->virtual_methods[i];
return result;
}
/******************************************************************************
* *
* Paramètres : class = informations chargées à consulter. *
* format = représentation interne du format DEX à compléter. *
* *
* Description : Retrouve si possible le nom du fichier source d'une classe. *
* *
* Retour : Nom du fichier trouvé ou NULL si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_dex_class_get_source_file(const GDexClass *class, const GDexFormat *format)
{
const char *result; /* Trouvaille à renvoyer */
result = get_string_from_dex_pool(format, class->definition.source_file_idx);
return result;
}
/******************************************************************************
* *
* Paramètres : class = informations chargées à consulter. *
* lang = langage à utiliser pour la sortie humaine. *
* buffer = tampon mis à disposition pour la sortie. *
* format = informations chargées à consulter. *
* *
* Description : Procède à la décompilation complète d'une classe donnée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_dex_class_decompile(const GDexClass *class, GLangOutput *lang, GCodeBuffer *buffer, const GDexFormat *format)
{
GOpenidaType *type;
size_t i; /* Boucle de parcours */
/*
GBufferLine *line, GLangOutput *output)
for (i = 0; i < block->count; i++)
{
if (i > 0)
line = g_code_buffer_append_new_line(buffer);
*/
type = get_type_from_dex_pool(format, class->definition.class_idx);
//g_buffer_line_insert_text(line, BLC_ASSEMBLY, "{", 3, RTT_SIGNS);
//printf("Output :: %s\n", _g_openida_type_to_string(type, true));
g_lang_output_start_class(lang, buffer, type);
for (i = 0; i < class->vmethods_count; i++)
{
g_dex_method_decompile(class->virtual_methods[i], lang, buffer);
g_code_buffer_append_new_line_fixme(buffer);
}
for (i = 0; i < class->dmethods_count; i++)
{
g_dex_method_decompile(class->direct_methods[i], lang, buffer);
g_code_buffer_append_new_line_fixme(buffer);
}
g_lang_output_end_class(lang, buffer);
}
/******************************************************************************
* *
* Paramètres : format = représentation interne du format DEX à compléter. *
* *
* Description : Charge toutes les classes listées dans le contenu binaire. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_all_dex_classes(GDexFormat *format)
{
const dex_header *header; /* Raccourci d'usage */
uint32_t i; /* Boucle de parcours */
GDexClass *class; /* Représentation chargée */
header = &format->header;
for (i = 0; i < header->class_defs_size; i++)
{
class = g_dex_class_new(format, header->class_defs_off + i * sizeof(class_def_item));
if (class != NULL)
{
format->classes_count++;
format->classes = (GDexClass **)realloc(format->classes,
format->classes_count * sizeof(GDexClass *));
format->classes[format->classes_count - 1] = class;
}
}
return true;
}
/******************************************************************************
* *
* Paramètres : format = représentation interne du format DEX à compléter. *
* *
* Description : Enregistre toutes les méthodes des classes listées. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void register_all_dex_class_methods(GDexFormat *format)
{
size_t i; /* Boucle de parcours */
GBinFormat *bformat; /* Autre version du format */
bformat = G_BIN_FORMAT(format);
for (i = 0; i < format->classes_count; i++)
g_dex_class_register_method(format->classes[i], bformat);
}