summaryrefslogtreecommitdiff
path: root/plugins/dex/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dex/class.c')
-rw-r--r--plugins/dex/class.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/plugins/dex/class.c b/plugins/dex/class.c
new file mode 100644
index 0000000..bb2ae71
--- /dev/null
+++ b/plugins/dex/class.c
@@ -0,0 +1,576 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * class.c - manipulation des classes du format DEX
+ *
+ * Copyright (C) 2010-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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "class.h"
+
+
+#include <malloc.h>
+
+
+#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 */
+ bool has_data; /* Indicateur de présence */
+ class_data_item data; /* Contenu 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 *);
+
+/* Supprime toutes les références externes. */
+static void g_dex_class_dispose(GDexClass *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_dex_class_finalize(GDexClass *);
+
+/* 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)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_dex_class_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_dex_class_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 : class = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_dex_class_dispose(GDexClass *class)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (class->direct_methods != NULL)
+ for (i = 0; i < class->dmethods_count; i++)
+ if (class->direct_methods[i] != NULL)
+ g_object_unref(G_OBJECT(class->direct_methods[i]));
+
+ if (class->virtual_methods != NULL)
+ for (i = 0; i < class->vmethods_count; i++)
+ if (class->virtual_methods[i] != NULL)
+ g_object_unref(G_OBJECT(class->virtual_methods[i]));
+
+ G_OBJECT_CLASS(g_dex_class_parent_class)->dispose(G_OBJECT(class));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_dex_class_finalize(GDexClass *class)
+{
+ if (class->direct_methods != NULL)
+ free(class->direct_methods);
+
+ if (class->virtual_methods != NULL)
+ free(class->virtual_methods);
+
+ G_OBJECT_CLASS(g_dex_class_parent_class)->finalize(G_OBJECT(class));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = représentation interne du format DEX à consulter. *
+* def = définitions générales associées à la classe. *
+* *
+* Description : Crée une nouvelle représentation de classe issue de code. *
+* *
+* Retour : Composant GLib créé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
+{
+ GDexClass *result; /* Composant à retourner */
+ vmpa2t addr; /* Tête de lecture générique */
+ class_data_item data; /* Contenu de la classe */
+ GDataType *ctype; /* Type créé par la classe */
+ GBinFormat *base; /* Autre version du format */
+ uleb128_t index; /* Conservation du dernier id */
+ uleb128_t i; /* Boucle de parcours */
+ GDexMethod *method; /* Méthode chargée */
+ GBinRoutine *routine; /* Version interne de méthode */
+
+ result = g_object_new(G_TYPE_DEX_CLASS, NULL);
+
+ result->definition = *def;
+ result->has_data = (def->class_data_off != 0);
+
+ /* Interface vide ? */
+ if (!result->has_data)
+ {
+ result->dmethods_count = 0;
+ result->direct_methods = NULL;
+
+ result->vmethods_count = 0;
+ result->virtual_methods = NULL;
+
+ goto gdcn_done;
+
+ }
+
+ init_vmpa(&addr, def->class_data_off, VMPA_NO_VIRTUAL);
+
+ if (!read_dex_class_data_item(format, &addr, &data))
+ goto gdcn_bad_item;
+
+ result->data = data;
+
+ /**
+ * On évite ici les méthodes (virtuelles) non définies.
+ */
+ if (def->access_flags & ACC_ANNOTATION) goto gdcn_done;
+
+ ctype = get_type_from_dex_pool(format, def->class_idx);
+ if (ctype == NULL) goto gdcn_unknown_type;
+
+ base = G_BIN_FORMAT(format);
+
+ index = 0;
+
+ result->dmethods_count = data.direct_methods_size;
+ result->direct_methods = (GDexMethod **)calloc(result->dmethods_count, sizeof(GDexMethod *));
+
+ for (i = 0; i < data.direct_methods_size; i++)
+ {
+ method = g_dex_method_new_defined(format, &data.direct_methods[i], &index);
+ if (method == NULL) goto gdcn_bad_method;
+
+ result->direct_methods[i] = method;
+
+ /* Ajout à la liste des symboles */
+ if (g_dex_method_has_dex_body(method))
+ {
+ routine = g_dex_method_get_routine(method);
+
+ g_object_ref(G_OBJECT(ctype));
+ g_binary_routine_set_namespace(routine, ctype, ".");
+
+ g_binary_format_add_symbol(base, G_BIN_SYMBOL(routine));
+
+ }
+
+ }
+
+ index = 0;
+
+ result->vmethods_count = data.virtual_methods_size;
+ result->virtual_methods = (GDexMethod **)calloc(result->vmethods_count, sizeof(GDexMethod *));
+
+ for (i = 0; i < data.virtual_methods_size; i++)
+ {
+ method = g_dex_method_new_defined(format, &data.virtual_methods[i], &index);
+ if (method == NULL) goto gdcn_bad_method;
+
+ result->virtual_methods[i] = method;
+
+ /* Ajout à la liste des symboles */
+ if (g_dex_method_has_dex_body(method))
+ {
+ routine = g_dex_method_get_routine(method);
+
+ g_object_ref(G_OBJECT(ctype));
+ g_binary_routine_set_namespace(routine, ctype, ".");
+
+ g_binary_format_add_symbol(base, G_BIN_SYMBOL(routine));
+
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(ctype));
+
+ gdcn_done:
+
+ return result;
+
+ gdcn_bad_method:
+
+ g_object_unref(G_OBJECT(ctype));
+
+ gdcn_unknown_type:
+
+ gdcn_bad_item:
+
+ g_object_unref(G_OBJECT(result));
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = informations chargées à consulter. *
+* *
+* Description : Fournit la définition brute d'une classe. *
+* *
+* Retour : Données brutes issues du binaire chargé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const class_def_item *g_dex_class_get_definition(const GDexClass *class)
+{
+ return &class->definition;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = informations chargées à consulter. *
+* *
+* Description : Fournit la définition brute des données d'une classe. *
+* *
+* Retour : Données brutes issues du binaire chargé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const class_data_item *g_dex_class_get_data(const GDexClass *class)
+{
+ return (class->has_data ? &class->data : NULL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = informations chargées à consulter. *
+* virtual = précise la nature des méthodes ciblées. *
+* *
+* Description : Dénombre les méthodes chargées d'un type donné. *
+* *
+* Retour : Quantité de méthodes trouvées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_dex_class_count_methods(const GDexClass *class, bool virtual)
+{
+ size_t result; /* Compte à retourner */
+
+ if (virtual)
+ result = class->vmethods_count;
+ else
+ result = class->dmethods_count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = informations chargées à consulter. *
+* virtual = précise la nature des méthodes ciblées. *
+* index = indique l'indice de la méthode désirée. *
+* *
+* Description : Fournit une méthode chargée correspondant à un type donné. *
+* *
+* Retour : Quantité de méthodes trouvées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GDexMethod *g_dex_class_get_method(const GDexClass *class, bool virtual, size_t index)
+{
+ GDexMethod *result; /* Instance à renvoyer */
+
+ if (virtual)
+ result = class->virtual_methods[index];
+ else
+ result = class->direct_methods[index];
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = informations chargées à consulter. *
+* format = format permettant d'obtenir une adresse complète. *
+* *
+* Description : Intègre la méthode en tant que portion de code. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_dex_class_include_as_portion(const GDexClass *class, GExeFormat *format)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < class->dmethods_count; i++)
+ g_dex_method_include_as_portion(class->direct_methods[i], format);
+
+ for (i = 0; i < class->vmethods_count; i++)
+ g_dex_method_include_as_portion(class->virtual_methods[i], format);
+
+}
+
+
+/******************************************************************************
+* *
+* 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 */
+ phys_t offset; /* Emplacement de méthode */
+
+ result = NULL;
+
+#if 0 /* FIXME */
+ /*
+
+bool g_dex_method_get_offset(const GDexMethod *method, phys_t *offset)
+
+ if (!g_exe_format_translate_offset_into_vmpa(G_EXE_FORMAT(format), method->offset, &addr))
+ return;
+
+ */
+
+ 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];
+#endif
+
+ 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, NULL);
+
+ 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 : - *
+* *
+******************************************************************************/
+#if 0
+void g_dex_class_decompile(const GDexClass *class, GLangOutput *lang, GCodeBuffer *buffer, const GDexFormat *format)
+{
+
+#if 0
+ GDataType *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_append_text(line, BLC_ASSEMBLY, "{", 3, RTT_SIGNS, NULL);
+
+ //printf("Output :: %s\n", _g_data_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);
+
+
+
+#endif
+
+
+}
+#endif