diff options
Diffstat (limited to 'plugins/dex/pool.c')
-rw-r--r-- | plugins/dex/pool.c | 686 |
1 files changed, 686 insertions, 0 deletions
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; + +} |