/* Chrysalide - Outil d'analyse de fichiers binaires * dex-int.c - structures internes du format DEX * * Copyright (C) 2017-2020 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 Chrysalide. If not, see . */ #include "dex-int.h" #include #include #include #include #include #include /* ---------------------------------------------------------------------------------- */ /* 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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; result = true; content = G_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; content = G_KNOWN_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] * * inter = position intermédiaire à conserver. [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, vmpa2t *inter, string_data_item *str_data) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu binaire à lire */ size_t consumed; /* Taille effective des données*/ phys_t fullsize; /* Taille complète du contenu */ vmpa2t old; /* Sauvegarde de position */ uleb128_t i; /* Boucle de parcours */ phys_t maxsize; /* Taille maximale d'une unité */ const bin_t *tmp; /* Zone de parcours temporaire */ size_t used; /* Quantié d'octets consommés */ unichar_t ch; /* Unité de code MUTF-8 */ content = G_KNOWN_FORMAT(format)->content; result = g_binary_content_read_uleb128(content, pos, &str_data->utf16_size); if (result) { if (inter != NULL) copy_vmpa(inter, pos); consumed = 0; fullsize = g_binary_content_compute_size(content); copy_vmpa(&old, pos); for (i = 0; i < (str_data->utf16_size + 1) && result; i++) { if (i > 0) { copy_vmpa(pos, &old); advance_vmpa(pos, consumed); } /** * Théoriquement, les 4 octets maximaux pour l'encodage ne sont pas * forcément tous disponibles... * * Il est alors possible d'obtenir une erreur pour un caractère * légitime d'un octet. * * On borne donc la taille de la prochaine unité MUTF-8. */ maxsize = fullsize - get_phy_addr(pos); if (maxsize > 4) maxsize = 4; tmp = g_binary_content_get_raw_access(content, pos, maxsize); ch = decode_mutf8_char(tmp, maxsize, &used); if (IS_UTF8_ERROR(ch)) result = false; else consumed += used; if (i == str_data->utf16_size) result = (ch == 0x0); } copy_vmpa(pos, &old); if (result) { str_data->data = g_binary_content_get_raw_access(content, pos, consumed); 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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; content = G_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; content = G_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; content = G_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; content = G_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; content = G_KNOWN_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_KNOWN_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_KNOWN_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_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; result = true; content = G_KNOWN_FORMAT(format)->content; result &= g_binary_content_read_u32(content, pos, SRE_LITTLE, &list->size); list->list = (const 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_KNOWN_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_KNOWN_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_KNOWN_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_KNOWN_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_KNOWN_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 */ /* Respect de l'alignement sur 4 octets */ if (get_phy_addr(pos) % 4 != 0) return false; result = true; content = G_KNOWN_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_KNOWN_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_KNOWN_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_KNOWN_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); }