diff options
Diffstat (limited to 'plugins/dex')
-rwxr-xr-x | plugins/dex/Makefile.am | 25 | ||||
-rw-r--r-- | plugins/dex/class.c | 576 | ||||
-rw-r--r-- | plugins/dex/class.h | 89 | ||||
-rw-r--r-- | plugins/dex/core.c | 68 | ||||
-rw-r--r-- | plugins/dex/core.h | 38 | ||||
-rw-r--r-- | plugins/dex/dex-int.c | 1115 | ||||
-rwxr-xr-x | plugins/dex/dex-int.h | 177 | ||||
-rwxr-xr-x | plugins/dex/dex_def.h | 327 | ||||
-rwxr-xr-x | plugins/dex/format.c | 611 | ||||
-rwxr-xr-x | plugins/dex/format.h | 77 | ||||
-rw-r--r-- | plugins/dex/loading.c | 240 | ||||
-rw-r--r-- | plugins/dex/loading.h | 63 | ||||
-rw-r--r-- | plugins/dex/method.c | 489 | ||||
-rw-r--r-- | plugins/dex/method.h | 104 | ||||
-rw-r--r-- | plugins/dex/pool.c | 686 | ||||
-rw-r--r-- | plugins/dex/pool.h | 74 | ||||
-rw-r--r-- | plugins/dex/python/Makefile.am | 16 | ||||
-rw-r--r-- | plugins/dex/python/class.c | 107 | ||||
-rw-r--r-- | plugins/dex/python/class.h | 42 | ||||
-rw-r--r-- | plugins/dex/python/format.c | 287 | ||||
-rw-r--r-- | plugins/dex/python/format.h | 42 | ||||
-rw-r--r-- | plugins/dex/python/module.c | 95 | ||||
-rw-r--r-- | plugins/dex/python/module.h | 38 |
23 files changed, 5386 insertions, 0 deletions
diff --git a/plugins/dex/Makefile.am b/plugins/dex/Makefile.am new file mode 100755 index 0000000..a17b0f2 --- /dev/null +++ b/plugins/dex/Makefile.am @@ -0,0 +1,25 @@ + +lib_LTLIBRARIES = libdex.la + +libdex_la_SOURCES = \ + core.h core.c \ + class.h class.c \ + dex-int.h dex-int.c \ + dex_def.h \ + format.h format.c \ + loading.h loading.c \ + method.h method.c \ + pool.h pool.c + +libdex_la_LIBADD = \ + python/libdexpython.la + +libdex_la_LDFLAGS = \ + $(LIBPYTHON_LIBS) $(LIBPYGOBJECT_LIBS) + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) + +SUBDIRS = python 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 diff --git a/plugins/dex/class.h b/plugins/dex/class.h new file mode 100644 index 0000000..73dd5df --- /dev/null +++ b/plugins/dex/class.h @@ -0,0 +1,89 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * class.h - prototypes pour la 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/>. + */ + + +#ifndef _PLUGINS_DEX_CLASS_H +#define _PLUGINS_DEX_CLASS_H + + +#include <glib-object.h> + + +#include "format.h" +#include "method.h" + + + +#define G_TYPE_DEX_CLASS (g_dex_class_get_type()) +#define G_DEX_CLASS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DEX_CLASS, GDexClass)) +#define G_DEX_CLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DEX_CLASS, GDexClassClass)) +#define G_IS_DEX_CLASS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DEX_CLASS)) +#define G_IS_DEX_CLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DEX_CLASS)) +#define G_DEX_CLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DEX_CLASS, GDexClassClass)) + + + +/* Classe issue du code source (instance) */ +typedef struct _GDexClass GDexClass; + +/* Classe issue du code source (classe) */ +typedef struct _GDexClassClass GDexClassClass; + + + +/* Détermine le type d'une classe issue du code source. */ +GType g_dex_class_get_type(void); + +/* Crée une nouvelle représentation de classe issue de code. */ +GDexClass *g_dex_class_new(GDexFormat *, const class_def_item *); + +/* Fournit la définition brute d'une classe. */ +const class_def_item *g_dex_class_get_definition(const GDexClass *); + +/* Fournit la définition brute des données d'une classe. */ +const class_data_item *g_dex_class_get_data(const GDexClass *); + +/* Dénombre les méthodes chargées d'un type donné. */ +size_t g_dex_class_count_methods(const GDexClass *, bool); + +/* Fournit une méthode chargée correspondant à un type donné. */ +GDexMethod *g_dex_class_get_method(const GDexClass *, bool, size_t); + +/* Intègre la méthode en tant que portion de code. */ +void g_dex_class_include_as_portion(const GDexClass *, GExeFormat *); + +/* Retrouve si possible la méthode associée à une adresse. */ +GDexMethod *g_dex_class_find_method_by_address(const GDexClass *, vmpa_t); + +/* Retrouve si possible le nom du fichier source d'une classe. */ +const char *g_dex_class_get_source_file(const GDexClass *, const GDexFormat *); + +/* Procède à la décompilation complète d'une classe donnée. */ +//void g_dex_class_decompile(const GDexClass *, GLangOutput *, GCodeBuffer *, const GDexFormat *); + + + + + + + +#endif /* _PLUGINS_DEX_CLASS_H */ diff --git a/plugins/dex/core.c b/plugins/dex/core.c new file mode 100644 index 0000000..c69904c --- /dev/null +++ b/plugins/dex/core.c @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - intégration du support du format ELF + * + * Copyright (C) 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 "core.h" + + +#include <core/formats.h> +#include <plugins/plugin-def.h> + + +#include "format.h" +#include "python/module.h" + + + +DEFINE_CHRYSALIDE_PLUGIN("dex", "Add suport for the DEX format", "0.1.0", + RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* ref = espace de référencement global. * +* * +* Description : Prend acte du chargement du greffon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) +{ + bool result; /* Bilan à retourner */ + + result = register_format_matcher(dex_is_matching, NULL); + + if (result) + result = register_format_loader("dex", "Dalvik Executable format", g_dex_format_new); + + if (result) + result = add_format_dex_module_to_python_module(); + + return result; + +} diff --git a/plugins/dex/core.h b/plugins/dex/core.h new file mode 100644 index 0000000..9852948 --- /dev/null +++ b/plugins/dex/core.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour l'intégration du support du format ELF + * + * Copyright (C) 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/>. + */ + + +#ifndef _PLUGINS_DEX_CORE_H +#define _PLUGINS_DEX_CORE_H + + +#include <plugins/plugin.h> +#include <plugins/plugin-int.h> + + + +/* Prend acte du chargement du greffon. */ +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *); + + + +#endif /* _PLUGINS_DEX_CORE_H */ diff --git a/plugins/dex/dex-int.c b/plugins/dex/dex-int.c new file mode 100644 index 0000000..3f3eccb --- /dev/null +++ b/plugins/dex/dex-int.c @@ -0,0 +1,1115 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dex-int.c - structures internes 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 "dex-int.h" + + +#include <assert.h> +#include <malloc.h> + + +#include <i18n.h> + + +#include <common/endianness.h> +#include <plugins/dalvik/instruction-def.h> + + + +/* ---------------------------------------------------------------------------------- */ +/* DESCRIPTION DU FORMAT DALVIK */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* header = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une en-tête de programme DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_header(const GDexFormat *format, vmpa2t *pos, dex_header *header) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + size_t i; /* Boucle de parcours */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + for (i = 0; i < DEX_FILE_MAGIC_LEN && result; i++) + result = g_binary_content_read_u8(content, pos, &header->magic[i]); + + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->checksum); + + for (i = 0; i < 20 && result; i++) + result = g_binary_content_read_u8(content, pos, &header->signature[i]); + + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->file_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->header_size); + + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->endian_tag); + + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->link_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->link_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->map_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->string_ids_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->string_ids_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->type_ids_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->type_ids_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->proto_ids_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->proto_ids_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->field_ids_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->field_ids_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->method_ids_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->method_ids_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->class_defs_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->class_defs_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->data_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &header->data_off); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* ELEMENTS DE TABLE DES CONSTANTES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* str_id = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un identifiant de chaîne DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_string_id_item(const GDexFormat *format, vmpa2t *pos, string_id_item *str_id) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &str_id->string_data_off); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* str_data = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture de proriétés de chaîne DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_string_data_item(const GDexFormat *format, vmpa2t *pos, string_data_item *str_data) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_uleb128(content, pos, &str_data->utf16_size); + + if (result) + { + str_data->data = g_binary_content_get_raw_access(content, pos, str_data->utf16_size); + result = (str_data->data != NULL); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* item = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un identifiant de type DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_type_id_item(const GDexFormat *format, vmpa2t *pos, type_id_item *item) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &item->descriptor_idx); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* proto_id = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une description de prototype. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_proto_id_item(const GDexFormat *format, vmpa2t *pos, proto_id_item *proto_id) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &proto_id->shorty_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &proto_id->return_type_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &proto_id->parameters_off); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* field_id = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une description de champ. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_field_id_item(const GDexFormat *format, vmpa2t *pos, field_id_item *field_id) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u16(content, pos, SRE_LITTLE, &field_id->class_idx); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &field_id->type_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &field_id->name_idx); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* meth_id = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une description de méthode. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_method_id_item(const GDexFormat *format, vmpa2t *pos, method_id_item *meth_id) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u16(content, pos, SRE_LITTLE, &meth_id->class_idx); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &meth_id->proto_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &meth_id->name_idx); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* class_def = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture des propriétés d'une classe DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_class_def_item(const GDexFormat *format, vmpa2t *pos, class_def_item *class_def) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->class_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->access_flags); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->superclass_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->interfaces_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->source_file_idx); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->annotations_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->class_data_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &class_def->static_values_off); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* DESCRIPTION DE CLASSES DEX */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* field = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un champ quelconque DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_encoded_field(const GDexFormat *format, vmpa2t *pos, encoded_field *field) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_uleb128(content, pos, &field->field_idx_diff); + result &= g_binary_content_read_uleb128(content, pos, &field->access_flags); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* method = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une méthode quelconque DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_encoded_method(const GDexFormat *format, vmpa2t *pos, encoded_method *method) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + copy_vmpa(&method->origin, pos); + + result &= g_binary_content_read_uleb128(content, pos, &method->method_idx_diff); + result &= g_binary_content_read_uleb128(content, pos, &method->access_flags); + result &= g_binary_content_read_uleb128(content, pos, &method->code_off); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* item = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un type DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_type_item(const GDexFormat *format, vmpa2t *pos, type_item *item) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + content = G_BIN_FORMAT(format)->content; + + result = g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->type_idx); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* list = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une liste de types DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_type_list(const GDexFormat *format, vmpa2t *pos, type_list *list) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &list->size); + + list->list = (type_item *)g_binary_content_get_raw_access(content, pos, list->size * sizeof(type_item)); + result &= (list->list != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* item = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un contenu de classe DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_class_data_item(const GDexFormat *format, vmpa2t *pos, class_data_item *item) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + uleb128_t i; /* Boucle de parcours */ + + result = true; + + item->static_fields = NULL; + item->instance_fields = NULL; + item->direct_methods = NULL; + item->virtual_methods = NULL; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_uleb128(content, pos, &item->static_fields_size); + result &= g_binary_content_read_uleb128(content, pos, &item->instance_fields_size); + result &= g_binary_content_read_uleb128(content, pos, &item->direct_methods_size); + result &= g_binary_content_read_uleb128(content, pos, &item->virtual_methods_size); + + if (result && item->static_fields_size > 0) + { + item->static_fields = (encoded_field *)calloc(item->static_fields_size, sizeof(encoded_field)); + if (item->static_fields == NULL) item->static_fields_size = 0; + + for (i = 0; i < item->static_fields_size && result; i++) + result = read_dex_encoded_field(format, pos, &item->static_fields[i]); + + } + + if (result && item->instance_fields_size > 0) + { + item->instance_fields = (encoded_field *)calloc(item->instance_fields_size, sizeof(encoded_field)); + if (item->instance_fields == NULL) item->instance_fields_size = 0; + + for (i = 0; i < item->instance_fields_size && result; i++) + result = read_dex_encoded_field(format, pos, &item->instance_fields[i]); + + } + + if (result && item->direct_methods_size > 0) + { + item->direct_methods = (encoded_method *)calloc(item->direct_methods_size, sizeof(encoded_method)); + if (item->direct_methods == NULL) item->direct_methods_size = 0; + + for (i = 0; i < item->direct_methods_size && result; i++) + result = read_dex_encoded_method(format, pos, &item->direct_methods[i]); + + } + + if (result && item->virtual_methods_size > 0) + { + item->virtual_methods = (encoded_method *)calloc(item->virtual_methods_size, sizeof(encoded_method)); + if (item->virtual_methods == NULL) item->virtual_methods_size = 0; + + for (i = 0; i < item->virtual_methods_size && result; i++) + result = read_dex_encoded_method(format, pos, &item->virtual_methods[i]); + + } + + if (!result) + reset_dex_class_data_item(item); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_class_data_item(class_data_item *item) +{ + if (item->static_fields != NULL) + free(item->static_fields); + + if (item->instance_fields != NULL) + free(item->instance_fields); + + if (item->direct_methods != NULL) + free(item->direct_methods); + + if (item->virtual_methods != NULL) + free(item->virtual_methods); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* PORTION DE CODE EXECUTABLE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* pair = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une association exception <-> code. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_encoded_type_addr_pair(const GDexFormat *format, vmpa2t *pos, encoded_type_addr_pair *pair) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_uleb128(content, pos, &pair->type_idx); + result &= g_binary_content_read_uleb128(content, pos, &pair->addr); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* handler = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une association exception <-> code. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_encoded_catch_handler(const GDexFormat *format, vmpa2t *pos, encoded_catch_handler *handler) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + leb128_t count; /* Nombre de gestionnaires */ + leb128_t i; /* Boucle de parcours */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + handler->offset = get_phy_addr(pos); + + result &= g_binary_content_read_leb128(content, pos, &handler->size); + + count = leb128_abs(handler->size); + + if (count > 0 && result) + { + handler->handlers = (encoded_type_addr_pair *)calloc(count, sizeof(encoded_type_addr_pair)); + + for (i = 0; i < count && result; i++) + result &= read_dex_encoded_type_addr_pair(format, pos, &handler->handlers[i]); + + } + else handler->handlers = NULL; + + if (handler->size <= 0) + result &= g_binary_content_read_uleb128(content, pos, &handler->catch_all_addr); + + else + handler->catch_all_addr = ULEB128_MAX; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_encoded_catch_handler(encoded_catch_handler *handler) +{ + if (handler->handlers != NULL) + free(handler->handlers); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* list = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une association exception <-> code. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_encoded_catch_handler_list(const GDexFormat *format, vmpa2t *pos, encoded_catch_handler_list *list) +{ + bool result; /* Bilan à retourner */ + off_t saved_off; /* Sauvegarde de position */ + GBinContent *content; /* Contenu binaire à lire */ + uleb128_t i; /* Boucle de parcours */ + + result = true; + + saved_off = get_phy_addr(pos); + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_uleb128(content, pos, &list->size); + + if (list->size > 0 && result) + { + list->list = (encoded_catch_handler *)calloc(list->size, sizeof(encoded_catch_handler)); + + for (i = 0; i < list->size && result; i++) + { + result &= read_dex_encoded_catch_handler(format, pos, &list->list[i]); + if (result) list->list[i].offset -= saved_off; + } + + } + else list->list = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_encoded_catch_handler_list(encoded_catch_handler_list *list) +{ + uleb128_t i; /* Boucle de parcours */ + + if (list->list != NULL) + { + for (i = 0; i < list->size; i++) + reset_dex_encoded_catch_handler(&list->list[i]); + + free(list->list); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* item = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une association exception <-> code. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_try_item(const GDexFormat *format, vmpa2t *pos, try_item *item) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &item->start_addr); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->insn_count); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->handler_off); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* item = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'une portion de code DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_code_item(const GDexFormat *format, vmpa2t *pos, code_item *item) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + vmpa2t origin; /* Mémorisation d'une position */ + uint16_t padding; /* Eventuel alignement */ + uint16_t i; /* Boucle de parcours */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->registers_size); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->ins_size); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->outs_size); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &item->tries_size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &item->debug_info_off); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &item->insns_size); + + item->insns = (uint16_t *)g_binary_content_get_raw_access(content, pos, item->insns_size * sizeof(uint16_t)); + if (item->insns == NULL) goto rdci_bad_insns; + + /* Padding ? */ + if (item->tries_size > 0 && item->insns_size % 2 == 1) + { + copy_vmpa(&origin, pos); + + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &padding); + + if (padding != 0) + g_binary_format_add_error(G_BIN_FORMAT(format), BFE_SPECIFICATION, &origin, + _("Expected a null value as padding.")); + + } + + if (item->tries_size > 0 && result) + { + assert(get_phy_addr(pos) % 4 == 0); + + item->tries = (try_item *)calloc(item->tries_size, sizeof(try_item)); + if (item->tries == NULL) goto rdci_bad_tries; + + for (i = 0; i < item->tries_size && result; i++) + result &= read_dex_try_item(format, pos, &item->tries[i]); + + if (result) + { + item->handlers = (encoded_catch_handler_list *)calloc(1, sizeof(encoded_catch_handler_list)); + result &= read_dex_encoded_catch_handler_list(format, pos, item->handlers); + } + + else + item->handlers = NULL; + + } + + else + { + item->tries = NULL; + item->handlers = NULL; + } + + return result; + + rdci_bad_insns: + + item->tries = NULL; + + rdci_bad_tries: + + item->handlers = NULL; + + return false; + +} + + +/****************************************************************************** +* * +* Paramètres : item = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_code_item(code_item *item) +{ + if (item->tries != NULL) + free(item->tries); + + if (item->handlers != NULL) + { + reset_dex_encoded_catch_handler_list(item->handlers); + free(item->handlers); + } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* AIGUILLAGES DIVERS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* packed = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un contenu d'aiguillage compact. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_packed_switch(const GDexFormat *format, vmpa2t *pos, packed_switch *packed) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + uint16_t i; /* Boucle de parcours */ + + result = true; + + packed->targets = NULL; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &packed->ident); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &packed->size); + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &packed->first_key); + + if (result && packed->size > 0) + { + packed->targets = (uint32_t *)calloc(packed->size, sizeof(uint32_t)); + + for (i = 0; i < packed->size && result; i++) + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &packed->targets[i]); + + } + + if (!result) + reset_dex_packed_switch(packed); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : packed = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_packed_switch(packed_switch *packed) +{ + if (packed->targets != NULL) + free(packed->targets); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* sparse = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un contenu d'aiguillage dispersé. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_sparse_switch(const GDexFormat *format, vmpa2t *pos, sparse_switch *sparse) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + uint16_t i; /* Boucle de parcours */ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + sparse->keys = NULL; + sparse->targets = NULL; + + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &sparse->ident); + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &sparse->size); + + if (result && sparse->size > 0) + { + sparse->keys = (uint32_t *)calloc(sparse->size, sizeof(uint32_t)); + sparse->targets = (uint32_t *)calloc(sparse->size, sizeof(uint32_t)); + + for (i = 0; i < sparse->size && result; i++) + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &sparse->keys[i]); + + for (i = 0; i < sparse->size && result; i++) + result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &sparse->targets[i]); + + } + + if (!result) + reset_dex_sparse_switch(sparse); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : sparse = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_sparse_switch(sparse_switch *sparse) +{ + if (sparse->keys != NULL) + free(sparse->keys); + + if (sparse->targets != NULL) + free(sparse->targets); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* pos = position de début de lecture. [OUT] * +* dsxitch = structure lue à retourner. [OUT] * +* * +* Description : Procède à la lecture d'un contenu d'aiguillage Dex interne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_dex_switch(const GDexFormat *format, vmpa2t *pos, dex_switch *dswitch) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à lire */ + uint16_t ident; /* Pseudo-code d'identification*/ + + result = true; + + content = G_BIN_FORMAT(format)->content; + + result &= g_binary_content_read_u16(content, pos, SRE_LITTLE, &ident); + + /** + * La tête de lecture n'est pas mise à jour volontairement ! + */ + + if (result) + { + if (ident == DPO_PACKED_SWITCH) + result = read_dex_packed_switch(format, pos, (packed_switch *)dswitch); + + else if (ident == DPO_SPARSE_SWITCH) + result = read_dex_sparse_switch(format, pos, (sparse_switch *)dswitch); + + else + result = false; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dswitch = structure à nettoyer. * +* * +* Description : Supprime tous les éléments chargés en mémoire à la lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_dex_switch(dex_switch *dswitch) +{ + if (dswitch->packed.ident == DPO_PACKED_SWITCH) + reset_dex_packed_switch((packed_switch *)dswitch); + else + reset_dex_sparse_switch((sparse_switch *)dswitch); + +} diff --git a/plugins/dex/dex-int.h b/plugins/dex/dex-int.h new file mode 100755 index 0000000..60d2f4d --- /dev/null +++ b/plugins/dex/dex-int.h @@ -0,0 +1,177 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dex-int.h - prototypes pour les structures internes 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/>. + */ + + +#ifndef _PLUGINS_DEX_DEX_INT_H +#define _PLUGINS_DEX_DEX_INT_H + + +#include <format/executable-int.h> + + +#include "class.h" +#include "dex_def.h" +#include "format.h" + + + +/* Format d'exécutable DEX (instance) */ +struct _GDexFormat +{ + GExeFormat parent; /* A laisser en premier */ + + dex_header header; /* En-tête du programme */ + + GDataType **types; /* Types partagés pour Dalvik */ + GBinVariable **fields; /* Champs de données partagés */ + GDexClass **classes; /* Classes retrouvées */ + +}; + +/* Format d'exécutable DEX (classe) */ +struct _GDexFormatClass +{ + GExeFormatClass parent; /* A laisser en premier */ + +}; + + +/* Retrouve si possible la méthode associée à une adresse. */ +GDexMethod *g_dex_format_find_method_by_address(const GDexFormat *, vmpa_t); + +/* Dénombre le nombre de classes trouvées. */ +size_t g_dex_format_count_classes(const GDexFormat *); + +/* Fournit une classe du format chargée en mémoire. */ +GDexClass *g_dex_format_get_class(const GDexFormat *, size_t); + + +/* -------------------------- DESCRIPTION DU FORMAT DALVIK -------------------------- */ + + +/* Procède à la lecture d'une en-tête de programme DEX. */ +bool read_dex_header(const GDexFormat *, vmpa2t *, dex_header *); + + + +/* ------------------------ ELEMENTS DE TABLE DES CONSTANTES ------------------------ */ + + +/* Procède à la lecture d'un identifiant de chaîne DEX. */ +bool read_dex_string_id_item(const GDexFormat *, vmpa2t *, string_id_item *); + +/* Procède à la lecture de proriétés de chaîne DEX. */ +bool read_dex_string_data_item(const GDexFormat *, vmpa2t *, string_data_item *); + +/* Procède à la lecture d'un identifiant de type DEX. */ +bool read_dex_type_id_item(const GDexFormat *, vmpa2t *, type_id_item *); + +/* Procède à la lecture d'une description de prototype. */ +bool read_dex_proto_id_item(const GDexFormat *, vmpa2t *, proto_id_item *); + +/* Procède à la lecture d'une description de champ. */ +bool read_dex_field_id_item(const GDexFormat *, vmpa2t *, field_id_item *); + +/* Procède à la lecture d'une description de méthode. */ +bool read_dex_method_id_item(const GDexFormat *, vmpa2t *, method_id_item *); + +/* Procède à la lecture des propriétés d'une classe DEX. */ +bool read_dex_class_def_item(const GDexFormat *, vmpa2t *, class_def_item *); + + + +/* --------------------------- DESCRIPTION DE CLASSES DEX --------------------------- */ + + +/* Procède à la lecture d'un champ quelconque DEX. */ +bool read_dex_encoded_field(const GDexFormat *, vmpa2t *, encoded_field *); + +/* Procède à la lecture d'une méthode quelconque DEX. */ +bool read_dex_encoded_method(const GDexFormat *, vmpa2t *, encoded_method *); + +/* Procède à la lecture d'un type DEX. */ +bool read_dex_type_item(const GDexFormat *, vmpa2t *, type_item *); + +/* Procède à la lecture d'une liste de types DEX. */ +bool read_dex_type_list(const GDexFormat *, vmpa2t *, type_list *); + +/* Procède à la lecture d'un contenu de classe DEX. */ +bool read_dex_class_data_item(const GDexFormat *, vmpa2t *, class_data_item *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_class_data_item(class_data_item *); + + + +/* --------------------------- PORTION DE CODE EXECUTABLE --------------------------- */ + + +/* Procède à la lecture d'une association exception <-> code. */ +bool read_dex_encoded_type_addr_pair(const GDexFormat *, vmpa2t *, encoded_type_addr_pair *); + +/* Procède à la lecture d'une association exception <-> code. */ +bool read_dex_encoded_catch_handler(const GDexFormat *, vmpa2t *, encoded_catch_handler *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_encoded_catch_handler(encoded_catch_handler *); + +/* Procède à la lecture d'une association exception <-> code. */ +bool read_dex_encoded_catch_handler_list(const GDexFormat *, vmpa2t *, encoded_catch_handler_list *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_encoded_catch_handler_list(encoded_catch_handler_list *); + +/* Procède à la lecture d'une association exception <-> code. */ +bool read_dex_try_item(const GDexFormat *, vmpa2t *, try_item *); + +/* Procède à la lecture d'une portion de code DEX. */ +bool read_dex_code_item(const GDexFormat *, vmpa2t *, code_item *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_code_item(code_item *); + + + +/* ------------------------------- AIGUILLAGES DIVERS ------------------------------- */ + + +/* Procède à la lecture d'un contenu d'aiguillage compact. */ +bool read_dex_packed_switch(const GDexFormat *, vmpa2t *, packed_switch *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_packed_switch(packed_switch *); + +/* Procède à la lecture d'un contenu d'aiguillage dispersé. */ +bool read_dex_sparse_switch(const GDexFormat *, vmpa2t *, sparse_switch *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_sparse_switch(sparse_switch *); + +/* Procède à la lecture d'un contenu d'aiguillage Dex interne. */ +bool read_dex_switch(const GDexFormat *, vmpa2t *, dex_switch *); + +/* Supprime tous les éléments chargés en mémoire à la lecture. */ +void reset_dex_switch(dex_switch *); + + + +#endif /* _PLUGINS_DEX_DEX_INT_H */ diff --git a/plugins/dex/dex_def.h b/plugins/dex/dex_def.h new file mode 100755 index 0000000..1d2e0d7 --- /dev/null +++ b/plugins/dex/dex_def.h @@ -0,0 +1,327 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dex_def.h - liste des structures et constantes utilisées par le 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/>. + */ + + +#ifndef _PLUGINS_DEX_DEX_DEF_H +#define _PLUGINS_DEX_DEX_DEF_H + + +#include <common/leb128.h> + + + +/* -------------------------- DESCRIPTION DU FORMAT DALVIK -------------------------- */ + + +/* Identifiant magique "dex\n035\0" */ +#define DEX_FILE_MAGIC "\x64\x65\x78\x0a\x30\x33\x35\x00" +#define DEX_FILE_MAGIC_LEN 8 + +/* Types de boutisme */ +#define ENDIAN_CONSTANT 0x12345678 +#define REVERSE_ENDIAN_CONSTANT 0x78563412 + +/* Indice non valide */ +#define NO_INDEX 0xffffffff + + +/* En-tête de tout programe Dex */ +typedef struct _dex_header +{ + uint8_t magic[DEX_FILE_MAGIC_LEN]; /* Valeur magique du format */ + + uint32_t checksum; /* Somme de contrôle adler32 */ + uint8_t signature[20]; /* Emprunte SHA-1 du reste */ + uint32_t file_size; /* Taille du fichier */ + uint32_t header_size; /* Taille de cette en-tête */ + + uint32_t endian_tag; /* Boutisme du fichier */ + + uint32_t link_size; /* Taille de section 'liaisons'*/ + uint32_t link_off; /* Position de ladite section */ + uint32_t map_off; /* Position de la cartographie */ + uint32_t string_ids_size; /* Nombre de chaînes de carac. */ + uint32_t string_ids_off; /* Position de cette liste */ + uint32_t type_ids_size; /* Nom d'identifiant de type */ + uint32_t type_ids_off; /* Position de la liste */ + uint32_t proto_ids_size; /* Nombre de prototypes */ + uint32_t proto_ids_off; /* Position de la liste */ + uint32_t field_ids_size; /* Nombre de champs */ + uint32_t field_ids_off; /* Position de la liste */ + uint32_t method_ids_size; /* Nombre de méthodes */ + uint32_t method_ids_off; /* Position de la liste */ + uint32_t class_defs_size; /* Nombre de classes déclarées */ + uint32_t class_defs_off; /* Position de la liste */ + uint32_t data_size; /* Taille des données */ + uint32_t data_off; /* Début des données */ + +} dex_header; + + + +/* -------------------------- CONSTANTES POUR DEX DIVERSES -------------------------- */ + + +/* Définition des drapeaux d'accès */ + +#define ACC_PUBLIC 0x00001 /* Elément publique */ +#define ACC_PRIVATE 0x00002 /* Elément privé */ +#define ACC_PROTECTED 0x00004 /* Elément protégé */ +#define ACC_STATIC 0x00008 /* Elément statique */ +#define ACC_FINAL 0x00010 /* Non dérivable / modifiable */ +#define ACC_SYNCHRONIZED 0x00020 /* Pose de verrou automatique */ +#define ACC_VOLATILE 0x00040 /* Accès spécial threads */ +#define ACC_BRIDGE 0x00040 /* Méthode pont */ +#define ACC_TRANSIENT 0x00080 /* Pas de sérialisation */ +#define ACC_VARARGS 0x00080 /* Arguments variables */ +#define ACC_NATIVE 0x00100 /* Implémentation en code natif*/ +#define ACC_INTERFACE 0x00200 /* Interface */ +#define ACC_ABSTRACT 0x00400 /* Non instanciable directement*/ +#define ACC_STRICT 0x00800 /* Règle pour les flottants */ +#define ACC_SYNTHETIC 0x01000 /* Non défini dans le code */ +#define ACC_ANNOTATION 0x02000 /* Annotation */ +#define ACC_ENUM 0x04000 /* Enumération */ +#define ACC_CONSTRUCTOR 0x10000 /* Constructeur */ +#define ACC_DECLARED_SYNCHRONIZED 0x20000 /* Pose de verrou automatique */ + + + +/* ------------------------ ELEMENTS DE TABLE DES CONSTANTES ------------------------ */ + + +/* Chaîne de caractères */ + +typedef struct _string_id_item +{ + uint32_t string_data_off; /* Propriétés de la chaîne */ + +} string_id_item; + +typedef struct _string_data_item +{ + uleb128_t utf16_size; /* Taille du décodage */ + const uint8_t *data; /* Caractères terminés par '\0'*/ + +} string_data_item; + +/* Description d'un type */ +typedef struct _type_id_item +{ + uint32_t descriptor_idx; /* Description du type */ + +} type_id_item; + +/* Description d'un prototype */ +typedef struct _proto_id_item +{ + uint32_t shorty_idx; /* Description version courte */ + uint32_t return_type_idx; /* Type de retour */ + uint32_t parameters_off; /* Position des arguments */ + +} proto_id_item; + +/* Description d'un champ */ +typedef struct _field_id_item +{ + uint16_t class_idx; /* Classe d'appartenance */ + uint16_t type_idx; /* Type du champ */ + uint32_t name_idx; /* Nom du champ */ + +} field_id_item; + +/* Description d'une méthode */ +typedef struct _method_id_item +{ + uint16_t class_idx; /* Classe d'appartenance */ + uint16_t proto_idx; /* Prototype de la méthode */ + uint32_t name_idx; /* Nom de la méthode */ + +} method_id_item; + +/* Description d'une classe */ +typedef struct _class_def_item +{ + uint32_t class_idx; /* Type de la classe */ + uint32_t access_flags; /* Drapeaux d'accès déclarés */ + uint32_t superclass_idx; /* Type de la classe parente */ + uint32_t interfaces_off; /* Liste des interfaces */ + uint32_t source_file_idx; /* Fichier source d'origine */ + uint32_t annotations_off; /* Eventuelles annotations */ + uint32_t class_data_off; /* Données de la classe */ + uint32_t static_values_off; /* Initialisations statiques */ + +} class_def_item; + + + +/* --------------------------- DESCRIPTION DE CLASSES DEX --------------------------- */ + + +/* Propriétés d'une champ */ +typedef struct _encoded_field +{ + uleb128_t field_idx_diff; /* Description du champ */ + uleb128_t access_flags; /* Conditions d'accès */ + +} encoded_field; + +/* Propriétés d'une méthode */ +typedef struct _encoded_method +{ + uleb128_t method_idx_diff; /* Description de la méthode */ + uleb128_t access_flags; /* Conditions d'accès */ + uleb128_t code_off; /* Position du code associé */ + + vmpa2t origin; /* Rajout pour suivi interne */ + +} encoded_method; + +/* Type quelconque */ +typedef struct _type_item +{ + uint16_t type_idx; /* Indice dans la table adaptée*/ + +} type_item; + +/* Liste de types */ +typedef struct _type_list +{ + uint32_t size; /* Nombre d'éléments présents */ + type_item *list; /* Liste des éléments inscrits */ + +} type_list; + +/* Données de fonctionnement pour classe */ +typedef struct _class_data_item +{ + uleb128_t static_fields_size; /* Quantité de champs statiques*/ + uleb128_t instance_fields_size; /* Qté de champs instanciables */ + uleb128_t direct_methods_size; /* Qté de méthodes propres */ + uleb128_t virtual_methods_size; /* Qté de méthodes virtuelles */ + + encoded_field *static_fields; /* Champs statiques */ + encoded_field *instance_fields; /* Champs instanciables */ + encoded_method *direct_methods; /* Méthodes propres */ + encoded_method *virtual_methods; /* Méthodes virtuelles */ + +} class_data_item; + + + +/* --------------------------- PORTION DE CODE EXECUTABLE --------------------------- */ + + +/* Exception gérée */ +typedef struct _encoded_type_addr_pair +{ + uleb128_t type_idx; /* Type d'exception couverte */ + uleb128_t addr; /* Adresse du début du code */ + +} encoded_type_addr_pair; + +/* Ensemble d'exceptions prises en compte */ +typedef struct _encoded_catch_handler +{ + leb128_t size; /* Quantité d'exceptions */ + encoded_type_addr_pair *handlers; /* Gestionnaires explicites */ + uleb128_t catch_all_addr; /* Adresse par défaut */ + + /** + * Note : les spécifications indiquent que le champ handler_off de + * try_item renvoie vers le gestionnaire à partir de la base de la structure + * encoded_catch_handler_list. Comme la représentation interne de cette + * structure efface la représentation physique, on conserve en mémoire + * le décalage rencontré à la lecture dans un champ artificiel. + */ + phys_t offset; /* Position dans le binaire */ + +} encoded_catch_handler; + +/* Liste des différents gestionnaires d'exceptions */ +typedef struct _encoded_catch_handler_list +{ + uleb128_t size; /* Taille de la liste */ + encoded_catch_handler *list; /* Gestionnaires en place */ + +} encoded_catch_handler_list; + +/* Zone couverte en cas de pépin */ +typedef struct _try_item +{ + uint32_t start_addr; /* Adresse du début couvert */ + uint16_t insn_count; /* Nbre de doubles-octets gérés*/ + uint16_t handler_off; /* Indice du gestionnaire */ + +} try_item; + +/* Description de la zone */ +typedef struct _code_item +{ + uint16_t registers_size; /* Qté de registres utilisés */ + uint16_t ins_size; /* Nbre d'arguments en entrée */ + uint16_t outs_size; /* Nbre d'arguments en sortie */ + uint16_t tries_size; /* Qté de try/catch */ + uint32_t debug_info_off; /* Information de débogage */ + uint32_t insns_size; /* Nbre de blocs de 2 octets */ + + uint16_t *insns; /* Code exécutable */ + try_item *tries; /* Zone d'exceptions */ + encoded_catch_handler_list *handlers; /* Gestionnaires associés */ + +} code_item; + + + +/* ------------------------------- AIGUILLAGES DIVERS ------------------------------- */ + + +/* Aiguillage compressé */ +typedef struct _packed_switch +{ + uint16_t ident; /* Pseudo-code d'identification*/ + uint16_t size; /* Nombre d'entrées */ + uint32_t first_key; /* Première et plus petite clef*/ + uint32_t *targets; /* Cibles relatives */ + +} packed_switch; + +/* Aiguillage dispersé */ +typedef struct _sparse_switch +{ + uint16_t ident; /* Pseudo-code d'identification*/ + uint16_t size; /* Nombre d'entrées */ + uint32_t *keys; /* Clefs valeureuses */ + uint32_t *targets; /* Cibles relatives */ + +} sparse_switch; + +/* Manipulation interne */ +typedef union _dex_switch +{ + packed_switch packed; /* Modèle compact */ + sparse_switch sparse; /* Modèle dispersé */ + +} dex_switch; + + + +#endif /* _PLUGINS_DEX_DEX_DEF_H */ diff --git a/plugins/dex/format.c b/plugins/dex/format.c new file mode 100755 index 0000000..72d0dd5 --- /dev/null +++ b/plugins/dex/format.c @@ -0,0 +1,611 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.c - support 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 "format.h" + + +#include <string.h> + + +#include <i18n.h> +#include <core/global.h> +#include <plugins/pglist.h> + + +#include "dex-int.h" +#include "pool.h" + + + +/* Initialise la classe des formats d'exécutables DEX. */ +static void g_dex_format_class_init(GDexFormatClass *); + +/* Initialise une instance de format d'exécutable DEX. */ +static void g_dex_format_init(GDexFormat *); + +/* Supprime toutes les références externes. */ +static void g_dex_format_dispose(GDexFormat *); + +/* Procède à la libération totale de la mémoire. */ +static void g_dex_format_finalize(GDexFormat *); + +/* Informe quant au boutisme utilisé. */ +static SourceEndian g_dex_format_get_endianness(const GDexFormat *); + +/* Indique le type d'architecture visée par le format. */ +static const char *g_dex_format_get_target_machine(const GDexFormat *); + +/* Etend la définition des portions au sein d'un binaire. */ +static void g_dex_format_refine_portions(GDexFormat *); + +/* Fournit l'emplacement d'une section donnée. */ +static bool g_dex_format_get_section_range_by_name(const GDexFormat *, const char *, mrange_t *); + + + + + + + + + + + + + +/* Détermine tous les fichiers source indiqués. */ +//static void g_dex_format_find_all_sources(GDexFormat *); + +/* Procède à la décompilation complète du format. */ +static void g_dex_format_decompile(const GDexFormat *, void/*GCodeBuffer*/ *, const char *); + + + +/****************************************************************************** +* * +* Paramètres : content = contenu binaire à parcourir. * +* parent = éventuel format exécutable déjà chargé. * +* unused = adresse non utilisée ici. * +* key = identifiant de format trouvé ou NULL. [OUT] * +* * +* Description : Indique si le format peut être pris en charge ici. * +* * +* Retour : Conclusion de haut niveau sur la reconnaissance effectuée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +FormatMatchStatus dex_is_matching(GBinContent *content, GExeFormat *parent, void *unused, char **key) +{ + FormatMatchStatus result; /* Bilan à renvoyer */ + vmpa2t addr; /* Tête de lecture initiale */ + bool status; /* Bilan des accès mémoire */ + char magic[DEX_FILE_MAGIC_LEN]; /* Idenfiant standard */ + + + /* REMME */ + if (parent != NULL) return FMS_UNKNOWN; + + + init_vmpa(&addr, 0, VMPA_NO_VIRTUAL); + + status = g_binary_content_read_raw(content, &addr, DEX_FILE_MAGIC_LEN, (bin_t *)magic); + + status &= (memcmp(magic, DEX_FILE_MAGIC, DEX_FILE_MAGIC_LEN) == 0); + + if (status) + { + result = FMS_MATCHED; + *key = strdup(parent == NULL ? "dex" : "dexdbg"); + } + else + result = FMS_UNKNOWN; + + return result; + +} + + +/* Indique le type défini pour un format d'exécutable DEX. */ +G_DEFINE_TYPE(GDexFormat, g_dex_format, G_TYPE_EXE_FORMAT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des formats d'exécutables DEX. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_format_class_init(GDexFormatClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GBinFormatClass *fmt; /* Version en format basique */ + GExeFormatClass *exe; /* Version en exécutable */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_dex_format_dispose; + object->finalize = (GObjectFinalizeFunc)g_dex_format_finalize; + + fmt = G_BIN_FORMAT_CLASS(klass); + + fmt->get_endian = (format_get_endian_fc)g_dex_format_get_endianness; + + exe = G_EXE_FORMAT_CLASS(klass); + + exe->get_machine = (get_target_machine_fc)g_dex_format_get_target_machine; + exe->refine_portions = (refine_portions_fc)g_dex_format_refine_portions; + + exe->translate_phys = (translate_phys_fc)g_exe_format_without_virt_translate_offset_into_vmpa; + exe->translate_virt = (translate_virt_fc)g_exe_format_without_virt_translate_address_into_vmpa; + + exe->get_range_by_name = (get_range_by_name_fc)g_dex_format_get_section_range_by_name; + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance à initialiser. * +* * +* Description : Initialise une instance de format d'exécutable DEX. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_format_init(GDexFormat *format) +{ + GBinFormat *bin_format; /* Format parent à compléter #1*/ + + bin_format = G_BIN_FORMAT(format); + + bin_format->decompile = (format_decompile_fc)g_dex_format_decompile; + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_format_dispose(GDexFormat *format) +{ + G_OBJECT_CLASS(g_dex_format_parent_class)->dispose(G_OBJECT(format)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_format_finalize(GDexFormat *format) +{ + G_OBJECT_CLASS(g_dex_format_parent_class)->finalize(G_OBJECT(format)); + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu binaire à parcourir. * +* parent = éventuel format exécutable déjà chargé. * + status = barre de statut à tenir informée. * +* * +* Description : Prend en charge un nouveau format Dex. * +* * +* Retour : Adresse de la structure mise en place ou NULL en cas d'échec.* +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status) +{ + GDexFormat *result; /* Structure à retourner */ + GBinFormat *base; /* Version basique du format */ + GExeFormat *exe_format; /* Autre version du format */ + vmpa2t pos; /* Position de tête de lecture */ + wgroup_id_t gid; /* Identifiant pour les tâches */ + + result = g_object_new(G_TYPE_DEX_FORMAT, NULL); + + base = G_BIN_FORMAT(result); + exe_format = G_EXE_FORMAT(result); + + g_binary_format_set_content(base, content); + + init_vmpa(&pos, 0, VMPA_NO_VIRTUAL); + + if (!read_dex_header(result, &pos, &result->header)) + goto gdfn_error; + + + + /* TODO : vérifier que les *_id ne se chevauchent pas */ + + + gid = g_work_queue_define_work_group(get_work_queue()); + + if (!load_all_dex_types(result, gid, status)) + goto gdfn_error; + + if (!load_all_dex_fields(result, gid, status)) + goto gdfn_error; + + if (!load_all_dex_classes(result, gid, status)) + goto gdfn_error; + + preload_binary_format(PGA_FORMAT_PRELOAD, base, base->info, status); + + if (!g_executable_format_complete_loading(exe_format, status)) + goto gdfn_error; + + return base; + + gdfn_error: + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* * +* Description : Informe quant au boutisme utilisé. * +* * +* Retour : Indicateur de boutisme. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static SourceEndian g_dex_format_get_endianness(const GDexFormat *format) +{ + return SRE_LITTLE; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* * +* Description : Indique le type d'architecture visée par le format. * +* * +* Retour : Identifiant de l'architecture ciblée par le format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const char *g_dex_format_get_target_machine(const GDexFormat *format) +{ + return "dalvik"; + +} + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* main = couche de portions principale à raffiner. * +* * +* Description : Etend la définition des portions au sein d'un binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_format_refine_portions(GDexFormat *format) +{ + GExeFormat *exe_format; /* Autre version du format */ + size_t max; /* Nombre d'itérations prévues */ + size_t i; /* Boucle de parcours */ + + exe_format = G_EXE_FORMAT(format); + + max = g_dex_format_count_classes(format); + + for (i = 0; i < max; i++) + g_dex_class_include_as_portion(format->classes[i], exe_format); + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* name = nom de la section recherchée. * +* range = emplacement en mémoire à renseigner. [OUT] * +* * +* Description : Fournit l'emplacement d'une section donnée. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_dex_format_get_section_range_by_name(const GDexFormat *format, const char *name, mrange_t *range) +{ + bool result; /* Bilan à retourner */ + + result = false; + + return result; + +} + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : format = 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_format_find_method_by_address(const GDexFormat *format, vmpa_t addr) +{ + + return NULL; + + +#if 0 + GDexMethod *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < format->classes_count && result == NULL; i++) + result = g_dex_class_find_method_by_address(format->classes[i], addr); + + return result; +#endif + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à mettre à jour. * +* * +* Description : Détermine tous les fichiers source indiqués. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ +#if 0 +static void g_dex_format_find_all_sources(GDexFormat *format) +{ + +#if 0 + + GBinFormat *bf; /* Instance parente */ + size_t i; /* Boucle de parcours #1 */ + const char *source; /* Fichier source trouvé */ + bool found; /* Présence dans la liste */ + size_t k; /* Boucle de parcours #2 */ + + bf = G_BIN_FORMAT(format); + + for (i = 0; i < format->classes_count; i++) + { + source = g_dex_class_get_source_file(format->classes[i], format); + if (source == NULL) continue; + + found = false; + + for (k = 0; k < bf->src_count && !found; k++) + found = (strcmp(source, bf->src_files[k]) == 0); + + if (!found) + { + bf->src_files = (const char **)realloc(bf->src_files, + ++bf->src_count * sizeof(const char **)); + bf->src_files[bf->src_count - 1] = source; + } + + } + +#endif + +} +#endif + +/****************************************************************************** +* * +* 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 : - * +* * +******************************************************************************/ + +static void g_dex_format_decompile(const GDexFormat *format, void/*GCodeBuffer*/ *buffer, const char *filename) +{ + +#if 0 + + GLangOutput *lang; /* Langage de sortie */ + size_t i; /* Boucle de parcours */ + const char *source; /* Fichier source trouvé */ + + lang = g_java_output_new(); + + for (i = 0; i < format->classes_count; i++) + { + source = g_dex_class_get_source_file(format->classes[i], format); + if (source == NULL || strcmp(source, filename) != 0) continue; + + g_dex_class_decompile(format->classes[i], lang, buffer, format); + + + +#if 0 + GDataType *get_type_from_dex_pool(const GDexFormat *format, uint16_t index) + + + Décrit le type fourni sous forme de caractères. * +* * +* Retour : Chaîne à libérer de la mémoire après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *_g_data_type_to_string(const GDataType *type, bool simple) + +#endif + + } + + +#endif + +} + + + + + + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* * +* Description : Présente l'en-tête DEX du format chargé. * +* * +* Retour : Pointeur vers la description principale. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const dex_header *g_dex_format_get_header(const GDexFormat *format) +{ + return &format->header; + +} + + + + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* * +* Description : Dénombre le nombre de classes trouvées. * +* * +* Retour : Quantité de classes présentes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_dex_format_count_classes(const GDexFormat *format) +{ + return format->header.class_defs_size; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* index = indice de la classe visée. * +* * +* Description : Fournit une classe du format chargée en mémoire. * +* * +* Retour : Instance représentant une classe chargée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDexClass *g_dex_format_get_class(const GDexFormat *format, size_t index) +{ + /* TODO : ref() */ + + return format->classes[index]; + +} + + + + + diff --git a/plugins/dex/format.h b/plugins/dex/format.h new file mode 100755 index 0000000..0398b9c --- /dev/null +++ b/plugins/dex/format.h @@ -0,0 +1,77 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.h - prototypes pour le support 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/>. + */ + + +#ifndef _PLUGINS_DEX_FORMAT_H +#define _PLUGINS_DEX_FORMAT_H + + +#include <glib-object.h> +#include <stdbool.h> +#include <sys/types.h> + + +#include <core/formats.h> + + +#include "dex_def.h" + + + +#define G_TYPE_DEX_FORMAT g_dex_format_get_type() +#define G_DEX_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_dex_format_get_type(), GDexFormat)) +#define G_IS_DEX_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_dex_format_get_type())) +#define G_DEX_FORMAT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_dex_format_get_type(), GDexFormatIface)) +#define G_DEX_FORMAT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DEX_FORMAT, GDexFormatClass)) + + +/* Format d'exécutable DEX (instance) */ +typedef struct _GDexFormat GDexFormat; + +/* Format d'exécutable DEX (classe) */ +typedef struct _GDexFormatClass GDexFormatClass; + + +/* Indique si le format peut être pris en charge ici. */ +FormatMatchStatus dex_is_matching(GBinContent *, GExeFormat *, void *, char **); + +/* Indique le type défini pour un format d'exécutable DEX. */ +GType g_dex_format_get_type(void); + +/* Prend en charge un nouveau format DEX. */ +GBinFormat *g_dex_format_new(GBinContent *, GExeFormat *, GtkStatusStack *); + +/* Présente l'en-tête DEX du format chargé. */ +const dex_header *g_dex_format_get_header(const GDexFormat *); + +/* Redéfinition : classe issue du code source (instance) */ +typedef struct _GDexClass GDexClass; + +/* Dénombre le nombre de classes trouvées. */ +size_t g_dex_format_count_classes(const GDexFormat *); + +/* Fournit une classe du format chargée en mémoire. */ +GDexClass *g_dex_format_get_class(const GDexFormat *, size_t); + + + +#endif /* _PLUGINS_DEX_FORMAT_H */ diff --git a/plugins/dex/loading.c b/plugins/dex/loading.c new file mode 100644 index 0000000..c00d0c5 --- /dev/null +++ b/plugins/dex/loading.c @@ -0,0 +1,240 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * loading.c - chargements parallèles des éléments de la table globale du format Dex + * + * Copyright (C) 2016-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 "loading.h" + + +#include <i18n.h> +#include <glibext/delayed-int.h> +#include <gui/panels/log.h> + + +#include "pool.h" + + + +/* Fraction de routines à limiter (instance) */ +struct _GDexLoading +{ + GDelayedWork parent; /* A laisser en premier */ + + GDexFormat *format; /* Format à faire évoluer */ + + dex_loading_cb callback; /* Routine de traitement finale*/ + uint32_t begin; /* Point de départ du parcours */ + uint32_t end; /* Point d'arrivée exclu */ + + activity_id_t id; /* Identifiant pour messages */ + + bool *status; /* Bilan global constitué */ + +}; + +/* Fraction de routines à limiter (classe) */ +struct _GDexLoadingClass +{ + GDelayedWorkClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des tâches des chargements pour DEX. */ +static void g_dex_loading_class_init(GDexLoadingClass *); + +/* Initialise une tâche de chargements pour DEX. */ +static void g_dex_loading_init(GDexLoading *); + +/* Supprime toutes les références externes. */ +static void g_dex_loading_dispose(GDexLoading *); + +/* Procède à la libération totale de la mémoire. */ +static void g_dex_loading_finalize(GDexLoading *); + +/* Assure le chargement pour un format DEX en différé. */ +static void g_dex_loading_process(GDexLoading *, GtkStatusStack *); + + + +/* Indique le type défini pour les tâches de chargements pour format DEX. */ +G_DEFINE_TYPE(GDexLoading, g_dex_loading, G_TYPE_DELAYED_WORK); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tâches des chargements pour DEX. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_loading_class_init(GDexLoadingClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDelayedWorkClass *work; /* Version en classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_dex_loading_dispose; + object->finalize = (GObjectFinalizeFunc)g_dex_loading_finalize; + + work = G_DELAYED_WORK_CLASS(klass); + + work->run = (run_task_fc)g_dex_loading_process; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = instance à initialiser. * +* * +* Description : Initialise une tâche de chargements pour DEX. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_loading_init(GDexLoading *loading) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : loading = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_loading_dispose(GDexLoading *loading) +{ + G_OBJECT_CLASS(g_dex_loading_parent_class)->dispose(G_OBJECT(loading)); + +} + + +/****************************************************************************** +* * +* Paramètres : loading = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_loading_finalize(GDexLoading *loading) +{ + G_OBJECT_CLASS(g_dex_loading_parent_class)->finalize(G_OBJECT(loading)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = = ensemble d'instructions désassemblées. * +* begin = point de départ du parcours de liste. * +* end = point d'arrivée exclu du parcours. * +* id = identifiant du message affiché à l'utilisateur. * +* callback = routine de traitements particuliers. * +* status = bilan final à constituer. [OUT] * +* * +* Description : Crée une tâche de chargement pour DEX différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDexLoading *g_dex_loading_new(GDexFormat *format, uint32_t begin, uint32_t end, activity_id_t id, dex_loading_cb callback, bool *status) +{ + GDexLoading *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_DEX_LOADING, NULL); + + result->format = format; + + result->callback = callback; + result->begin = begin; + result->end = end; + + result->id = id; + + result->status = status; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : study = étude de routines à mener. * +* status = barre de statut à tenir informée. * +* * +* Description : Assure le chargement pour un format DEX en différé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_loading_process(GDexLoading *loading, GtkStatusStack *status) +{ + uint32_t i; /* Boucle de parcours */ + GObject *obj; /* Object chargé en mémoire */ + + for (i = loading->begin; i < loading->end && *(loading->status); i++) + { + obj = loading->callback(loading->format, i); + + if (obj != NULL) + g_object_unref(obj); + + else + { + *(loading->status) = false; + log_variadic_message(LMT_ERROR, _("Error while loading Dex pool item #%u!"), i); + } + + gtk_status_stack_update_activity_value(status, loading->id, 1); + + } + +} diff --git a/plugins/dex/loading.h b/plugins/dex/loading.h new file mode 100644 index 0000000..612f962 --- /dev/null +++ b/plugins/dex/loading.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * loading.h - prototypes pour les chargements parallèles des éléments de la table globale du format Dex + * + * Copyright (C) 2016-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/>. + */ + + +#ifndef _PLUGINS_DEX_LOADING_H +#define _PLUGINS_DEX_LOADING_H + + +#include <gtkext/gtkstatusstack.h> + + +#include "format.h" + + + +#define G_TYPE_DEX_LOADING g_dex_loading_get_type() +#define G_DEX_LOADING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_dex_loading_get_type(), GDexLoading)) +#define G_IS_DEX_LOADING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_dex_loading_get_type())) +#define G_DEX_LOADING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DEX_LOADING, GDexLoadingClass)) +#define G_IS_DEX_LOADING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DEX_LOADING)) +#define G_DEX_LOADING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DEX_LOADING, GDexLoadingClass)) + + +/* Fraction de loading à limiter (instance) */ +typedef struct _GDexLoading GDexLoading; + +/* Fraction de loading à limiter (classe) */ +typedef struct _GDexLoadingClass GDexLoadingClass; + + + +/* Extrait une représentation générique d'une table Dex. */ +typedef GObject * (* dex_loading_cb) (GDexFormat *, uint32_t); + + +/* Indique le type défini pour les tâches de chargements pour format DEX. */ +GType g_dex_loading_get_type(void); + +/* Crée une tâche de chargement pour DEX différée. */ +GDexLoading *g_dex_loading_new(GDexFormat *, uint32_t, uint32_t, activity_id_t, dex_loading_cb, bool *); + + + +#endif /* _PLUGINS_DEX_LOADING_H */ diff --git a/plugins/dex/method.c b/plugins/dex/method.c new file mode 100644 index 0000000..0f49154 --- /dev/null +++ b/plugins/dex/method.c @@ -0,0 +1,489 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * method.c - manipulation des methodes 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 "method.h" + + +#include <stddef.h> +#include <string.h> + + +#include <i18n.h> + + +#include "dex-int.h" +#include "pool.h" + + + + +/* Methode issue du code source (instance) */ +struct _GDexMethod +{ + GObject parent; /* A laisser en premier */ + + GBinRoutine *routine; /* Représentation interne */ + + /* FIXME : méthode interne seulement */ + encoded_method info; /* Propriétés de la méthode */ + bool has_body; /* Indication de présence */ + code_item body; /* Corps de la méthode */ + off_t offset; /* Position du code */ + +}; + +/* Methode issue du code source (classe) */ +struct _GDexMethodClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Procède à l'initialisation d'une methode issue du code. */ +static void g_dex_method_class_init(GDexMethodClass *); + +/* Procède à l'initialisation d'une methode issue du code. */ +static void g_dex_method_init(GDexMethod *); + +/* Supprime toutes les références externes. */ +static void g_dex_method_dispose(GDexMethod *); + +/* Procède à la libération totale de la mémoire. */ +static void g_dex_method_finalize(GDexMethod *); + + + +/* Détermine le type d'une methode issue du code source. */ +G_DEFINE_TYPE(GDexMethod, g_dex_method, G_TYPE_OBJECT); + + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'une methode issue du code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_method_class_init(GDexMethodClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_dex_method_dispose; + object->finalize = (GObjectFinalizeFunc)g_dex_method_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : method = composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'une methode issue du code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_method_init(GDexMethod *method) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_method_dispose(GDexMethod *method) +{ + if (method->routine != NULL) + g_object_unref(G_OBJECT(method->routine)); + + G_OBJECT_CLASS(g_dex_method_parent_class)->dispose(G_OBJECT(method)); + +} + + +/****************************************************************************** +* * +* Paramètres : method = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dex_method_finalize(GDexMethod *method) +{ + if (method->has_body) + reset_dex_code_item(&method->body); + + G_OBJECT_CLASS(g_dex_method_parent_class)->finalize(G_OBJECT(method)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* seed = graine des informations à extraire. * +* last = dernier indice utilisé (à mettre à jour). [OUT] * +* * +* Description : Crée une nouvelle représentation de methode issue de code. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDexMethod *g_dex_method_new_defined(GDexFormat *format, const encoded_method *seed, uleb128_t *last) +{ + GDexMethod *result; /* Composant à retourner */ + vmpa2t addr; /* Tête de lecture générique */ + code_item item; /* Corps de la méthode */ + phys_t ins_offset; /* Position physique du code */ + mrange_t range; /* Emplacement du code associé */ + + *last += seed->method_idx_diff; + + result = get_method_from_dex_pool(format, *last); + + if (result == NULL) + return NULL; + + result->info = *seed; + + result->has_body = (seed->code_off > 0); + + if (result->has_body) + { + init_vmpa(&addr, seed->code_off, VMPA_NO_VIRTUAL); + + if (!read_dex_code_item(format, &addr, &item)) + goto gdmnd_bad_code_item; + + ins_offset = seed->code_off + offsetof(code_item, insns); + + if (!g_exe_format_translate_offset_into_vmpa(G_EXE_FORMAT(format), ins_offset, &addr)) + goto gdmnd_bad_translation; + + result->body = item; + + result->offset = ins_offset; + + init_mrange(&range, &addr, item.insns_size * sizeof(uint16_t)); + g_binary_symbol_set_range(G_BIN_SYMBOL(result->routine), &range); + + } + + return result; + + gdmnd_bad_translation: + + reset_dex_code_item(&item); + + gdmnd_bad_code_item: + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter.* +* method_id = informations de base quant à la méthode. * +* * +* Description : Crée une nouvelle représentation de methode vide. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDexMethod *g_dex_method_new_callable(GDexFormat *format, const method_id_item *method_id) +{ + GDexMethod *result; /* Composant à retourner */ + const char *name; /* Nom de la routine finale */ + GBinRoutine *routine; /* Routine représentée */ + + result = NULL; + + name = get_string_from_dex_pool(format, method_id->name_idx, NULL); + if (name == NULL) goto gdmne_exit; + + routine = get_prototype_from_dex_pool(format, method_id->proto_idx); + if (routine == NULL) goto gdmne_exit; + + g_binary_routine_set_name(routine, strdup(name)); + + result = g_object_new(G_TYPE_DEX_METHOD, NULL); + + result->routine = routine; + + gdmne_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne de la méthode à consulter. * +* * +* Description : Fournit les indications Dex concernant la méthode. * +* * +* Retour : Données brutes du binaire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const encoded_method *g_dex_method_get_dex_info(const GDexMethod *method) +{ + return &method->info; + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne de la méthode à consulter. * +* * +* Description : Indique si du code est rattaché à une méthode Dex. * +* * +* Retour : true si la méthode n'est pas abstraite ni native. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_dex_method_has_dex_body(const GDexMethod *method) +{ + return method->has_body; + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne de la méthode à consulter. * +* * +* Description : Fournit les indications Dex relatives au corps de la méthode.* +* * +* Retour : Données brutes du binaire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const code_item *g_dex_method_get_dex_body(const GDexMethod *method) +{ + return (method->has_body ? &method->body : NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne du format DEX à consulter. * +* * +* Description : Fournit la routine Chrysalide correspondant à la méthode. * +* * +* Retour : Instance de routine mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinRoutine *g_dex_method_get_routine(const GDexMethod *method) +{ + GBinRoutine *result; /* Instance à retourner */ + + result = method->routine; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne du format DEX à 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_method_include_as_portion(const GDexMethod *method, GExeFormat *format) +{ + vmpa2t addr; /* Emplacement dans le binaire */ + GBinPortion *new; /* Nouvelle portion définie */ + + /* Si la taille est nulle, on ne fait rien */ + if (method->info.access_flags & ACC_NATIVE) + return; + + if (!method->has_body) + return; + + if (!g_exe_format_translate_offset_into_vmpa(format, method->offset, &addr)) + return; + + new = g_binary_portion_new(BPC_CODE, &addr, method->body.insns_size * sizeof(uint16_t)); + + g_binary_portion_set_desc(new, _("Dalvik code")); + + g_binary_portion_set_rights(new, PAC_READ | PAC_EXEC); + + g_exe_format_include_portion(format, new, &method->info.origin); + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne du format DEX à consulter. * +* offset = position physique à renseigner. [OUT] * +* * +* Description : Indique la position de la méthode au sein du binaire. * +* * +* Retour : Validiter de la position dans le contenu binaire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_dex_method_get_offset(const GDexMethod *method, phys_t *offset) +{ + bool result; /* Indication à retourner */ + + result = method->has_body; + + if (result) + *offset = method->offset; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : method = représentation interne du format DEX à consulter. * +* index = indice de base comme seul indice. * +* * +* Description : Fournit des indications sur la nature d'une variable donnée. * +* * +* Retour : Indentifiant complet d'une variable utilisée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +DexVariableIndex g_dex_method_get_variable(const GDexMethod *method, uint32_t index) +{ + const encoded_method *info; /* Propriétés de la méthode */ + const code_item *body; /* Corps de la méthode */ + uint32_t pivot; /* Bascule pour les arguments */ + + info = &method->info; + body = &method->body; + + /* S'agit-il d'un argument ? */ + + pivot = body->registers_size - body->ins_size; + + if (!(info->access_flags & ACC_STATIC)) + pivot++; + + if (index >= pivot) + return (index - pivot) | DVI_ARGUMENT; + + /* S'agit-il de "this" ? */ + + if (!(info->access_flags & ACC_STATIC) + && index == (body->registers_size - body->ins_size)) + return DVI_THIS; + + /* Alors il s'agit d'une variable locale... */ + + return index | DVI_LOCAL; + +} + + +/****************************************************************************** +* * +* Paramètres : method = informations chargées à consulter. * +* lang = langage à utiliser pour la sortie humaine. * +* buffer = tampon mis à disposition pour la sortie. * +* * +* Description : Procède à la décompilation complète d'une routine donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ +#if 0 +void g_dex_method_decompile(const GDexMethod *method, GLangOutput *lang, GCodeBuffer *buffer) +{ + g_binary_routine_print_code(method->routine, lang, buffer, true); + +} +#endif diff --git a/plugins/dex/method.h b/plugins/dex/method.h new file mode 100644 index 0000000..6716713 --- /dev/null +++ b/plugins/dex/method.h @@ -0,0 +1,104 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * method.h - prototypes pour la manipulation des methodes 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/>. + */ + + +#ifndef _PLUGINS_DEX_METHOD_H +#define _PLUGINS_DEX_METHOD_H + + +#include <glib-object.h> + + +#include <analysis/routine.h> + + +#include "dex_def.h" +#include "format.h" + + + +#define G_TYPE_DEX_METHOD (g_dex_method_get_type()) +#define G_DEX_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DEX_METHOD, GDexMethod)) +#define G_DEX_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DEX_METHOD, GDexMethodClass)) +#define G_IS_DEX_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DEX_METHOD)) +#define G_IS_DEX_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DEX_METHOD)) +#define G_DEX_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DEX_METHOD, GDexMethodClass)) + + + +/* Methode issue du code source (instance) */ +typedef struct _GDexMethod GDexMethod; + +/* Methode issue du code source (classe) */ +typedef struct _GDexMethodClass GDexMethodClass; + + +/* Détermination des variables */ +typedef enum _DexVariableIndex +{ + /* Indices... */ + + DVI_LOCAL = (1 << 29), + DVI_THIS = (1 << 30), + DVI_ARGUMENT = (1 << 31) + +} DexVariableIndex; + +#define DVI_INDEX(v) (v & ~(7 << 29)) + + +/* Détermine le type d'une methode issue du code source. */ +GType g_dex_method_get_type(void); + +/* Crée une nouvelle représentation de methode issue de code. */ +GDexMethod *g_dex_method_new_defined(GDexFormat *, const encoded_method *, uleb128_t *); + +/* Crée une nouvelle représentation de methode vide. */ +GDexMethod *g_dex_method_new_callable(GDexFormat *, const method_id_item *); + +/* Fournit les indications Dex concernant la méthode. */ +const encoded_method *g_dex_method_get_dex_info(const GDexMethod *); + +/* Indique si du code est rattaché à une méthode Dex. */ +bool g_dex_method_has_dex_body(const GDexMethod *); + +/* Fournit les indications Dex relatives au corps de la méthode. */ +const code_item *g_dex_method_get_dex_body(const GDexMethod *); + +/* Fournit la routine Chrysalide correspondant à la méthode. */ +GBinRoutine *g_dex_method_get_routine(const GDexMethod *); + +/* Intègre la méthode en tant que portion de code. */ +void g_dex_method_include_as_portion(const GDexMethod *, GExeFormat *); + +/* Indique la position de la méthode au sein du binaire. */ +bool g_dex_method_get_offset(const GDexMethod *method, phys_t *); + +/* Fournit des indications sur la nature d'une variable donnée. */ +DexVariableIndex g_dex_method_get_variable(const GDexMethod *, uint32_t); + +/* Procède à la décompilation complète d'une routine donnée. */ +//void g_dex_method_decompile(const GDexMethod *, GLangOutput *, GCodeBuffer *); + + + +#endif /* _PLUGINS_DEX_METHOD_H */ diff --git a/plugins/dex/pool.c b/plugins/dex/pool.c new file mode 100644 index 0000000..3c97da3 --- /dev/null +++ b/plugins/dex/pool.c @@ -0,0 +1,686 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pool.c - extraction des informations issues des tables globales + * + * 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 "pool.h" + + +#include <malloc.h> +#include <string.h> + + +#include <i18n.h> +#include <core/global.h> +#include <format/mangling/demangler.h> +#include <format/mangling/dex/context.h> + + +#include "dex-int.h" +#include "loading.h" + + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à analyser. * +* * +* Description : Charge en mémoire toutes les chaînes trouvées. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool find_all_dex_strings(GDexFormat *format) +{ + GBinFormat *base; /* Autre version du format */ + uint32_t i; /* Boucle de parcours */ + mrange_t range; /* Couverture associée */ + const char *text; /* Texte issu du binaire */ + GBinSymbol *symbol; /* Nouveau symbole construit */ + char *label; /* Désignation de la chaîne */ + + base = G_BIN_FORMAT(format); + + for (i = 0; i < format->header.string_ids_size; i++) + { + text = get_string_from_dex_pool(format, i, &range); + if (text == NULL) continue; + + symbol = g_binary_symbol_new(&range, STP_STRING); + + label = create_string_label(base, get_mrange_addr(&range), get_mrange_length(&range)); + + g_binary_symbol_set_alt_label(symbol, label); + + free(label); + + g_binary_format_add_symbol(base, symbol); + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* index = index du type recherchée. * +* range = éventuelle couverture à renseigner ou NULL. [OUT] * +* * +* Description : Extrait une chaîne de caractères d'une table DEX. * +* * +* Retour : Chaîne de caractères trouvées ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *get_string_from_dex_pool(const GDexFormat *format, uint32_t index, mrange_t *range) +{ + off_t pos; /* Tête de lecture */ + vmpa2t addr; /* Tête de lecture générique */ + string_id_item str_id; /* Identifiant de chaîne */ + string_data_item str_data; /* Description de chaîne */ + vmpa2t start; /* Début de la chaîne */ + phys_t diff; /* Avancée de tête de lecture */ + + if (index >= format->header.string_ids_size) + return NULL; + + pos = format->header.string_ids_off + index * sizeof(string_id_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_string_id_item(format, &addr, &str_id)) + return NULL; + + pos = str_id.string_data_off; + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_string_data_item(format, &addr, &str_data)) + return NULL; + + if (range != NULL) + { + init_vmpa(&start, pos, VMPA_NO_VIRTUAL); + diff = compute_vmpa_diff(&start, &addr); + + init_mrange(range, &start, diff); + + } + + return (const char *)str_data.data; + +} + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à compléter. * +* gid = groupe de travail impliqué. * + status = barre de statut à tenir informée. * +* * +* Description : Charge en mémoire l'ensemble des types du format DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_all_dex_types(GDexFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + guint runs_count; /* Qté d'exécutions parallèles */ + uint32_t run_size; /* Volume réparti par exécution*/ + GWorkQueue *queue; /* Gestionnaire de différés */ + activity_id_t msg; /* Message de progression */ + guint i; /* Boucle de parcours */ + uint32_t begin; /* Début de bloc de traitement */ + uint32_t end; /* Fin d'un bloc de traitement */ + GDexLoading *loading; /* Tâche de chargement à lancer*/ + + result = true; + + /* Préparation du réceptacle */ + + format->types = (GDataType **)calloc(format->header.type_ids_size, sizeof(GDataType *)); + + /* Lancement des chargements */ + + runs_count = g_get_num_processors(); + + run_size = format->header.type_ids_size / runs_count; + + queue = get_work_queue(); + + msg = gtk_status_stack_add_activity(status, _("Loading all types from the Dex pool..."), + format->header.type_ids_size); + + for (i = 0; i < runs_count; i++) + { + begin = i * run_size; + + if ((i + 1) == runs_count) + end = format->header.type_ids_size; + else + end = begin + run_size; + + loading = g_dex_loading_new(format, begin, end, msg, + (dex_loading_cb)get_type_from_dex_pool, &result); + + g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid); + + } + + g_work_queue_wait_for_completion(queue, gid); + + gtk_status_stack_remove_activity(status, msg); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* index = index du type recherchée. * +* * +* Description : Extrait une représentation de type d'une table DEX. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDataType *get_type_from_dex_pool(GDexFormat *format, uint32_t index) +{ + GDataType *result; /* Instance à retourner */ + phys_t pos; /* Tête de lecture */ + vmpa2t addr; /* Tête de lecture générique */ + type_id_item type_id; /* Définition de la classe */ + string_id_item str_id; /* Identifiant de chaîne */ + string_data_item str_data; /* Description de chaîne */ + + result = NULL; + + if (index >= format->header.type_ids_size) + goto gtfdp_error; + + if (format->types[index] == NULL) + { + pos = format->header.type_ids_off + index * sizeof(type_id_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_type_id_item(format, &addr, &type_id)) + goto gtfdp_error; + + pos = format->header.string_ids_off + type_id.descriptor_idx * sizeof(string_id_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_string_id_item(format, &addr, &str_id)) + goto gtfdp_error; + + pos = str_id.string_data_off; + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_string_data_item(format, &addr, &str_data)) + goto gtfdp_error; + + format->types[index] = demangle_type(G_TYPE_DEX_DEMANGLER, (char *)str_data.data); + + } + + result = format->types[index]; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + gtfdp_error: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à compléter. * +* gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * +* * +* Description : Charge en mémoire l'ensemble des champs du format DEX. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_all_dex_fields(GDexFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + guint runs_count; /* Qté d'exécutions parallèles */ + uint32_t run_size; /* Volume réparti par exécution*/ + GWorkQueue *queue; /* Gestionnaire de différés */ + activity_id_t msg; /* Message de progression */ + guint i; /* Boucle de parcours */ + uint32_t begin; /* Début de bloc de traitement */ + uint32_t end; /* Fin d'un bloc de traitement */ + GDexLoading *loading; /* Tâche de chargement à lancer*/ + + result = true; + + /* Préparation du réceptacle */ + + format->fields = (GBinVariable **)calloc(format->header.field_ids_size, sizeof(GBinVariable *)); + + /* Lancement des chargements */ + + runs_count = g_get_num_processors(); + + run_size = format->header.field_ids_size / runs_count; + + queue = get_work_queue(); + + msg = gtk_status_stack_add_activity(status, _("Loading all fields from the Dex pool..."), + format->header.field_ids_size); + + for (i = 0; i < runs_count; i++) + { + begin = i * run_size; + + if ((i + 1) == runs_count) + end = format->header.field_ids_size; + else + end = begin + run_size; + + loading = g_dex_loading_new(format, begin, end, msg, + (dex_loading_cb)get_field_from_dex_pool, &result); + + g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid); + + } + + g_work_queue_wait_for_completion(queue, gid); + + gtk_status_stack_remove_activity(status, msg); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* index = index du champ recherché. * +* * +* Description : Extrait une représentation de champ d'une table DEX. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinVariable *get_field_from_dex_pool(GDexFormat *format, uint32_t index) +{ + GBinVariable *result; /* Instance à retourner */ + phys_t pos; /* Tête de lecture */ + vmpa2t addr; /* Tête de lecture générique */ + field_id_item field_id; /* Description du champ */ + GDataType *type; /* Type du champ */ + const char *name; /* Désignation humaine */ + GBinVariable *field; /* Instance nouvelle à définir */ + GDataType *owner; /* Propriétaire du champ */ + + result = NULL; + + if (index >= format->header.field_ids_size) + goto gffdp_error; + + if (format->fields[index] == NULL) + { + pos = format->header.field_ids_off + index * sizeof(field_id_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_field_id_item(format, &addr, &field_id)) + goto gffdp_error; + + type = get_type_from_dex_pool(format, field_id.type_idx); + if (type == NULL) goto gffdp_error; + + name = get_string_from_dex_pool(format, field_id.name_idx, NULL); + if (name == NULL) goto gffdp_bad_name; + + field = g_binary_variable_new(type); + g_binary_variable_set_name(field, name); + + if (field_id.class_idx != NO_INDEX) + { + owner = get_type_from_dex_pool(format, field_id.class_idx); + if (owner == NULL) goto gffdp_bad_owner; + + g_binary_variable_set_owner(field, owner); + + } + + format->fields[index] = field; + + } + + result = format->fields[index]; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + gffdp_error: + + return result; + + gffdp_bad_owner: + + g_object_ref(G_OBJECT(type)); + g_object_unref(G_OBJECT(result)); + + gffdp_bad_name: + + g_object_unref(G_OBJECT(type)); + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* index = index de la routine recherchée. * +* * +* Description : Extrait une représentation de routine d'une table DEX. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinRoutine *get_prototype_from_dex_pool(GDexFormat *format, uint32_t index) +{ + GBinRoutine *result; /* Instance à retourner */ + phys_t pos; /* Tête de lecture */ + vmpa2t addr; /* Tête de lecture générique */ + proto_id_item proto_id; /* Prototype de routine */ + GDataType *type; /* Type de retour */ + const char *name; /* Description compressée */ + type_list args; /* Liste des arguments */ + uint32_t i; /* Boucle de parcours */ + GBinVariable *arg; /* Argument reconstitué */ + + result = NULL; + + /** + * Les prototypes sont personnalisés après chargement. + * Donc on ne peut pas conserver de version globale comme pour + * les autres éléments de la table des constantes. + */ + + if (index >= format->header.proto_ids_size) + goto grfdp_error; + + pos = format->header.proto_ids_off + index * sizeof(proto_id_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_proto_id_item(format, &addr, &proto_id)) + goto grfdp_error; + + /* Type de retour */ + + type = get_type_from_dex_pool(format, proto_id.return_type_idx); + + /* Nom de la méthode */ + + name = get_string_from_dex_pool(format, proto_id.shorty_idx, NULL); + + /* Liste des arguments */ + + pos = proto_id.parameters_off; + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + result = g_binary_routine_new();/////////////////////// + + if (read_dex_type_list(format, &addr, &args)) + for (i = 0; i < args.size; i++) + { + type = get_type_from_dex_pool(format, args.list[i].type_idx); + if (type == NULL) continue; + + arg = g_binary_variable_new(type); + g_binary_routine_add_arg(result, arg);/////////////////////// + + } + + /* Mise en place finale */ + + ///////result = demangle_routine(G_TYPE_DEX_DEMANGLER, name); + + g_binary_routine_set_name(result, strdup("...")); + +#if 1 + if (result != NULL)/////////////////////// + g_binary_routine_set_return_type(result, type); +#endif + + /* + if (result != NULL) + g_object_ref(G_OBJECT(result)); + */ + + grfdp_error: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* index = index de la classe recherchée. * +* * +* Description : Extrait une représentation de méthode d'une table DEX. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDexMethod *get_method_from_dex_pool(GDexFormat *format, uint32_t index) +{ + GDexMethod *result; /* Instance à retourner */ + phys_t pos; /* Tête de lecture */ + vmpa2t addr; /* Tête de lecture générique */ + method_id_item method_id; /* Définition de la méthode */ + + result = NULL; + + if (index >= format->header.method_ids_size) + goto gmfdp_error; + + /** + * On charge ici une méthode à partir de la définition de 'method_id_item'. + * + * C'est l'élément 'encoded_method' qui référence cette cette définition et qui + * applique ensuite les attributs finaux de la méthode. La classe parente est + * précisée en outre bien en amont. + * + * Comme une même définition peut donc servir à plusieurs instances, + * on ne peut pas conserver un tableau d'allocations communes. + */ + + pos = format->header.method_ids_off + index * sizeof(method_id_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_method_id_item(format, &addr, &method_id)) + goto gmfdp_error; + + result = g_dex_method_new_callable(format, &method_id); + + gmfdp_error: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à compléter. * +* gid = groupe de travail impliqué. * + status = barre de statut à tenir informée. * +* * +* 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, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + guint runs_count; /* Qté d'exécutions parallèles */ + uint32_t run_size; /* Volume réparti par exécution*/ + GWorkQueue *queue; /* Gestionnaire de différés */ + activity_id_t msg; /* Message de progression */ + guint i; /* Boucle de parcours */ + uint32_t begin; /* Début de bloc de traitement */ + uint32_t end; /* Fin d'un bloc de traitement */ + GDexLoading *loading; /* Tâche de chargement à lancer*/ + + result = true; + + /* Préparation du réceptacle */ + + format->classes = (GDexClass **)calloc(format->header.class_defs_size, sizeof(GDexClass *)); + + /* Lancement des chargements */ + + runs_count = g_get_num_processors(); + + run_size = format->header.class_defs_size / runs_count; + + queue = get_work_queue(); + + msg = gtk_status_stack_add_activity(status, _("Loading all classes from the Dex pool..."), + format->header.class_defs_size); + + for (i = 0; i < runs_count; i++) + { + begin = i * run_size; + + if ((i + 1) == runs_count) + end = format->header.class_defs_size; + else + end = begin + run_size; + + loading = g_dex_loading_new(format, begin, end, msg, + (dex_loading_cb)get_class_from_dex_pool, &result); + + g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid); + + } + + g_work_queue_wait_for_completion(queue, gid); + + gtk_status_stack_remove_activity(status, msg); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = représentation interne du format DEX à consulter. * +* index = index de la classe recherchée. * +* * +* Description : Extrait une représentation de classe d'une table DEX. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDexClass *get_class_from_dex_pool(GDexFormat *format, uint32_t index) +{ + GDexClass *result; /* Instance à retourner */ + phys_t pos; /* Tête de lecture */ + vmpa2t addr; /* Tête de lecture générique */ + class_def_item class_def; /* Définition de la classe */ + + result = NULL; + + if (index >= format->header.class_defs_size) + goto gcfdp_error; + + if (format->classes[index] == NULL) + { + pos = format->header.class_defs_off + index * sizeof(class_def_item); + init_vmpa(&addr, pos, VMPA_NO_VIRTUAL); + + if (!read_dex_class_def_item(format, &addr, &class_def)) + goto gcfdp_error; + + format->classes[index] = g_dex_class_new(format, &class_def); + + } + + result = format->classes[index]; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + gcfdp_error: + + return result; + +} diff --git a/plugins/dex/pool.h b/plugins/dex/pool.h new file mode 100644 index 0000000..56bcd64 --- /dev/null +++ b/plugins/dex/pool.h @@ -0,0 +1,74 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pool.h - prototypes pour l'extraction des informations issues des tables globales + * + * 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/>. + */ + + +#ifndef _PLUGINS_DEX_POOL_H +#define _PLUGINS_DEX_POOL_H + + +#include <analysis/routine.h> +#include <glibext/delayed.h> + + +#include "class.h" +#include "format.h" +#include "method.h" + + + +/* Charge en mémoire toutes les chaînes trouvées. */ +bool find_all_dex_strings(GDexFormat *); + +/* Extrait une chaîne de caractères d'une table DEX. */ +const char *get_string_from_dex_pool(const GDexFormat *, uint32_t, mrange_t *); + + + + + +/* Charge en mémoire l'ensemble des types du format DEX. */ +bool load_all_dex_types(GDexFormat *, wgroup_id_t, GtkStatusStack *); + +/* Extrait une représentation de type d'une table DEX. */ +GDataType *get_type_from_dex_pool(GDexFormat *, uint32_t); + +/* Charge en mémoire l'ensemble des champs du format DEX. */ +bool load_all_dex_fields(GDexFormat *, wgroup_id_t, GtkStatusStack *); + +/* Extrait une représentation de champ d'une table DEX. */ +GBinVariable *get_field_from_dex_pool(GDexFormat *, uint32_t); + +/* Extrait une représentation de routine d'une table DEX. */ +GBinRoutine *get_prototype_from_dex_pool(GDexFormat *, uint32_t); + +/* Extrait une représentation de méthode d'une table DEX. */ +GDexMethod *get_method_from_dex_pool(GDexFormat *, uint32_t); + +/* Charge toutes les classes listées dans le contenu binaire. */ +bool load_all_dex_classes(GDexFormat *, wgroup_id_t, GtkStatusStack *); + +/* Extrait une représentation de classe d'une table DEX. */ +GDexClass *get_class_from_dex_pool(GDexFormat *, uint32_t); + + + +#endif /* _PLUGINS_DEX_POOL_H */ diff --git a/plugins/dex/python/Makefile.am b/plugins/dex/python/Makefile.am new file mode 100644 index 0000000..fc6f85e --- /dev/null +++ b/plugins/dex/python/Makefile.am @@ -0,0 +1,16 @@ + +noinst_LTLIBRARIES = libdexpython.la + +libdexpython_la_SOURCES = \ + class.h class.c \ + format.h format.c \ + module.h module.c + + +libdexpython_la_LDFLAGS = + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dex/python/class.c b/plugins/dex/python/class.c new file mode 100644 index 0000000..ec1c3f7 --- /dev/null +++ b/plugins/dex/python/class.c @@ -0,0 +1,107 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * class.c - équivalent Python du fichier "plugins/dex/class.c" + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "class.h" + + +#include <pygobject.h> + + +#include <plugins/pychrysa/helpers.h> + + +#include "../class.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_dex_class_type(void) +{ + static PyMethodDef py_dex_class_methods[] = { + { NULL } + }; + + static PyGetSetDef py_dex_class_getseters[] = { + { NULL } + }; + + static PyTypeObject py_dex_class_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.format.dex.DexClass", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "PyChrysalide Dex class.", + + .tp_methods = py_dex_class_methods, + .tp_getset = py_dex_class_getseters + + }; + + return &py_dex_class_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.format.dex.DexClass'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_dex_class(PyObject *module) +{ + PyTypeObject *py_dex_class_type; /* Type Python 'DexClass' */ + PyObject *dict; /* Dictionnaire du module */ + + py_dex_class_type = get_python_dex_class_type(); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_DEX_CLASS, py_dex_class_type, &PyGObject_Type)) + return false; + + return true; + +} diff --git a/plugins/dex/python/class.h b/plugins/dex/python/class.h new file mode 100644 index 0000000..02ec882 --- /dev/null +++ b/plugins/dex/python/class.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * class.h - prototypes pour l'équivalent Python du fichier "plugins/dex/class.h" + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_DEX_PYTHON_CLASS_H +#define _PLUGINS_DEX_PYTHON_CLASS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_dex_class_type(void); + +/* Prend en charge l'objet 'pychrysalide.format.dex.DexClass'. */ +bool register_python_dex_class(PyObject *module); + + + +#endif /* _PLUGINS_DEX_PYTHON_CLASS_H */ diff --git a/plugins/dex/python/format.c b/plugins/dex/python/format.c new file mode 100644 index 0000000..74f6eae --- /dev/null +++ b/plugins/dex/python/format.c @@ -0,0 +1,287 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.c - équivalent Python du fichier "plugins/dex/format.c" + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "format.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysa/helpers.h> +#include <plugins/pychrysa/analysis/binary.h> +#include <plugins/pychrysa/analysis/content.h> +#include <plugins/pychrysa/format/executable.h> + + +#include "../class.h" +#include "../format.h" + + + +/* Crée un nouvel objet Python de type 'DexFormat'. */ +static PyObject *py_dex_format_new(PyTypeObject *, PyObject *, PyObject *); + +/* Dénombre le nombre de classes trouvées. */ +static PyObject *py_dex_format_count_classes(PyObject *, PyObject *); + +/* Fournit une classe du format chargée en mémoire. */ +static PyObject *py_dex_format_get_class(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'DexFormat'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_dex_format_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + PyObject *content_obj; /* Objet pour le contenu */ + PyObject *parent_obj; /* Objet pour le parent */ + PyObject *status_obj; /* Objet pour la progression */ + int ret; /* Bilan de lecture des args. */ + GBinContent *content; /* Instance GLib du contenu */ + GExeFormat *parent; /* Instance GLib du parent */ + GtkStatusStack *status; /* Instance GTK de suivi */ + GBinFormat *format; /* Création GLib à transmettre */ + + ret = PyArg_ParseTuple(args, "OOO", &content_obj, &parent_obj, &status_obj); + if (!ret) return NULL; + + ret = PyObject_IsInstance(content_obj, (PyObject *)get_python_binary_content_type()); + if (!ret) + { + PyErr_SetString(PyExc_TypeError, _("The first argument must be an instance of BinContent.")); + return NULL; + } + + content = G_BIN_CONTENT(pygobject_get(content_obj)); + + if (parent_obj == Py_None) + parent = NULL; + + else + { + ret = PyObject_IsInstance(parent_obj, (PyObject *)get_python_executable_format_type()); + if (!ret) + { + PyErr_SetString(PyExc_TypeError, _("The second argument must be a container format or None.")); + return NULL; + } + + parent = G_EXE_FORMAT(pygobject_get(parent_obj)); + + } + + if (status_obj == Py_None) + status = NULL; + + else + { + ret = PyObject_IsInstance(status_obj, (PyObject *)get_python_binary_content_type()); + if (!ret) + { + PyErr_SetString(PyExc_TypeError, _("The third argument must be a status bar object or None.")); + return NULL; + } + + status = GTK_STATUS_STACK(pygobject_get(status_obj)); + + } + + format = g_dex_format_new(content, parent, status); + if (format == NULL) + { + PyErr_SetString(PyExc_RuntimeError, _("Unable to load the DEX format.")); + return NULL; + } + + result = pygobject_new(G_OBJECT(format)); + + g_object_unref(format); + + return (PyObject *)result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un binaire. * +* args = arguments fournis à l'appel. * +* * +* Description : Dénombre le nombre de classes trouvées. * +* * +* Retour : Quantité de classes présentes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_dex_format_count_classes(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + GDexFormat *format; /* Version native */ + size_t count; /* Quantité à retourner */ + + format = G_DEX_FORMAT(pygobject_get(self)); + + count = g_dex_format_count_classes(format); + + result = PyLong_FromLong(count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un binaire. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit une classe du format chargée en mémoire. * +* * +* Retour : Instance représentant une classe chargée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_dex_format_get_class(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + int ret; /* Bilan de lecture des args. */ + int index; /* Indice de la classe */ + GDexFormat *format; /* Version native */ + GDexClass *class; /* Classe à communiquer */ + + ret = PyArg_ParseTuple(args, "i", &index); + if (!ret) Py_RETURN_NONE; + + format = G_DEX_FORMAT(pygobject_get(self)); + + class = g_dex_format_get_class(format, index); + if (class == NULL) Py_RETURN_NONE; + + result = pygobject_new(G_OBJECT(class)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_dex_format_type(void) +{ + static PyMethodDef py_dex_format_methods[] = { + { + "count_classes", (PyCFunction)py_dex_format_count_classes, + METH_NOARGS, + "count_classes($self, /)\n--\n\nCount the quantity of loaded Dex classes." + }, + { + "get_class", (PyCFunction)py_dex_format_get_class, + METH_VARARGS, + "get_class($self, index, /)\n--\n\nProvide a given loaded Dex class." + }, + { NULL } + }; + + static PyGetSetDef py_dex_format_getseters[] = { + { NULL } + }; + + static PyTypeObject py_dex_format_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.format.dex.DexFormat", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "PyChrysalide Dex format", + + .tp_methods = py_dex_format_methods, + .tp_getset = py_dex_format_getseters, + .tp_new = (newfunc)py_dex_format_new + + }; + + return &py_dex_format_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.format.dex.DexFormat'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_dex_format(PyObject *module) +{ + PyTypeObject *py_dex_format_type; /* Type Python 'DexFormat' */ + PyObject *dict; /* Dictionnaire du module */ + + py_dex_format_type = get_python_dex_format_type(); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_DEX_FORMAT, + py_dex_format_type, get_python_executable_format_type())) + return false; + + return true; + +} diff --git a/plugins/dex/python/format.h b/plugins/dex/python/format.h new file mode 100644 index 0000000..4a365c9 --- /dev/null +++ b/plugins/dex/python/format.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.h - prototypes pour l'équivalent Python du fichier "plugins/dex/format.h" + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_DEX_PYTHON_FORMAT_H +#define _PLUGINS_DEX_PYTHON_FORMAT_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_dex_format_type(void); + +/* Prend en charge l'objet 'pychrysalide.format.dex.DexFormat'. */ +bool register_python_dex_format(PyObject *); + + + +#endif /* _PLUGINS_DEX_PYTHON_FORMAT_H */ diff --git a/plugins/dex/python/module.c b/plugins/dex/python/module.c new file mode 100644 index 0000000..8d5092d --- /dev/null +++ b/plugins/dex/python/module.c @@ -0,0 +1,95 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire dex en tant que module + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysa/access.h> + + +#include "class.h" +#include "format.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'format.dex' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_format_dex_module_to_python_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + int ret; /* Bilan d'un appel */ + + static PyModuleDef py_chrysalide_dex_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.format.dex", + .m_doc = "Python module for Chrysalide.format.dex", + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.format"); + + module = PyModule_Create(&py_chrysalide_dex_module); + if (module == NULL) return false; + + ret = PyState_AddModule(super, &py_chrysalide_dex_module); + if (ret != 0) goto loading_failed; + + ret = _PyImport_FixupBuiltin(module, "pychrysalide.format.dex"); + if (ret != 0) goto loading_failed; + + Py_INCREF(module); + ret = PyModule_AddObject(super, "dex", module); + if (ret != 0) goto loading_failed; + + result = register_python_dex_class(module); + + if (result) + result = register_python_dex_format(module); + + loading_failed: + + return result; + +} diff --git a/plugins/dex/python/module.h b/plugins/dex/python/module.h new file mode 100644 index 0000000..d1540d7 --- /dev/null +++ b/plugins/dex/python/module.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire dex en tant que module + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_DEX_PYTHON_MODULE_H +#define _PLUGINS_DEX_PYTHON_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'format.dex' au module Python. */ +bool add_format_dex_module_to_python_module(void); + + + +#endif /* _PLUGINS_DEX_PYTHON_MODULE_H */ |