/* Chrysalide - Outil d'analyse de fichiers binaires * strsym.c - gestion des chaînes dans un binaire * * Copyright (C) 2018 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 "strsym.h" #include #include #include #include #include "symbol-int.h" #include "../common/alloc.h" /* ----------------------- VITRINE POUR CHAINES DE CARACTERES ----------------------- */ /* Symbole pour chaîne de caractères (instance) */ struct _GStrSymbol { GBinSymbol parent; /* A laisser en premier */ StringEncodingType encoding; /* Encodage de la chaîne liée */ union { GBinContent *content; /* Conteneur d'origine */ char *string; /* Données utilisables */ }; bool has_content; /* Choix dans l'union */ }; /* Symbole pour chaîne de caractères (classe) */ struct _GStrSymbolClass { GBinSymbolClass parent; /* A laisser en premier */ }; /* Initialise la classe des chaînes de caractères. */ static void g_string_symbol_class_init(GStrSymbolClass *); /* Initialise une instance de chaîne de caractères. */ static void g_string_symbol_init(GStrSymbol *); /* Supprime toutes les références externes. */ static void g_string_symbol_dispose(GStrSymbol *); /* Procède à la libération totale de la mémoire. */ static void g_string_symbol_finalize(GStrSymbol *); /* Vérifie la pertinence de l'encodage attribué à une chaîne. */ static void g_string_symbol_check_encoding(GStrSymbol *); /* ---------------------------------------------------------------------------------- */ /* VITRINE POUR CHAINES DE CARACTERES */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un symbole d'exécutable. */ /* G_DEFINE_TYPE_WITH_CODE(GStrSymbol, g_string_symbol, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_string_symbol_interface_init)); */ G_DEFINE_TYPE(GStrSymbol, g_string_symbol, G_TYPE_BIN_SYMBOL); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des chaînes de caractères. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_string_symbol_class_init(GStrSymbolClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_string_symbol_dispose; object->finalize = (GObjectFinalizeFunc)g_string_symbol_finalize; } /****************************************************************************** * * * Paramètres : symbol = instance à initialiser. * * * * Description : Initialise une instance de chaîne de caractères. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_string_symbol_init(GStrSymbol *symbol) { } /****************************************************************************** * * * Paramètres : symbol = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_string_symbol_dispose(GStrSymbol *symbol) { if (symbol->has_content) g_object_unref(G_OBJECT(symbol->content)); G_OBJECT_CLASS(g_string_symbol_parent_class)->dispose(G_OBJECT(symbol)); } /****************************************************************************** * * * Paramètres : symbol = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_string_symbol_finalize(GStrSymbol *symbol) { if (!symbol->has_content) free(symbol->string); G_OBJECT_CLASS(g_string_symbol_parent_class)->finalize(G_OBJECT(symbol)); } /****************************************************************************** * * * Paramètres : format = format binaire reconnu. * * range = espace couvert par le nouveau symbole. * * encoding = encodage de la chaîne de caractères à représenter.* * * * Description : Crée un nouveau symbole pour chaîne de caractères. * * * * Retour : Adresse de l'instance mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBinSymbol *g_string_symbol_new_read_only(GBinFormat *format, const mrange_t *range, StringEncodingType encoding) { GStrSymbol *result; /* Nouveau symbole à renvoyer */ GBinSymbol *parent; /* Type d'instance parent */ result = g_object_new(G_TYPE_STR_SYMBOL, NULL); parent = G_BIN_SYMBOL(result); g_binary_symbol_set_range(parent, range); g_binary_symbol_set_target_type(parent, STP_RO_STRING); result->encoding = encoding; result->content = g_binary_format_get_content(format); result->has_content = true; g_string_symbol_check_encoding(result); return G_BIN_SYMBOL(result); } /****************************************************************************** * * * Paramètres : string = contenu de la chaîne de caractères. * * addr = emplacement de cette chaîne virtuelle. * * encoding = encodage de la chaîne de caractères à représenter.* * * * Description : Crée un nouveau symbole pour chaîne de caractères. * * * * Retour : Adresse de l'instance mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBinSymbol *g_string_symbol_new_dynamic(const char *string, const vmpa2t *addr, StringEncodingType encoding) { GStrSymbol *result; /* Nouveau symbole à renvoyer */ GBinSymbol *parent; /* Type d'instance parent */ mrange_t range; /* Emplacement à constituer */ result = g_object_new(G_TYPE_STR_SYMBOL, NULL); parent = G_BIN_SYMBOL(result); init_mrange(&range, addr, strlen(string)); g_binary_symbol_set_range(parent, &range); g_binary_symbol_set_target_type(parent, STP_DYN_STRING); result->encoding = encoding; result->string = strdup(string); result->has_content = false; g_string_symbol_check_encoding(result); return G_BIN_SYMBOL(result); } /****************************************************************************** * * * Paramètres : symbol = symbole à venir consulter. * * * * Description : Vérifie la pertinence de l'encodage attribué à une chaîne. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_string_symbol_check_encoding(GStrSymbol *symbol) { const char *string; /* Données à analyser */ switch (symbol->encoding) { case SET_ASCII: break; case SET_UTF_8: case SET_MUTF_8: string = g_string_symbol_get_utf8(symbol); if (!g_utf8_validate(string, -1, NULL)) symbol->encoding = SET_ASCII; break; case SET_GUESS: string = g_string_symbol_get_utf8(symbol); if (g_str_is_ascii(string)) symbol->encoding = SET_ASCII; else if (g_utf8_validate(string, -1, NULL)) symbol->encoding = SET_UTF_8; else symbol->encoding = SET_ASCII; break; } } /****************************************************************************** * * * Paramètres : symbol = symbole à venir consulter. * * * * Description : Fournit l'encodage d'une chaîne de caractères. * * * * Retour : Type d'encodage utilisé. * * * * Remarques : - * * * ******************************************************************************/ StringEncodingType g_string_symbol_get_encoding(const GStrSymbol *symbol) { StringEncodingType result; /* Type à retourner */ result = symbol->encoding; assert(result != SET_GUESS); return result; } /****************************************************************************** * * * Paramètres : symbol = symbole à venir consulter. * * * * Description : Fournit la chaîne de caractères du symbole. * * * * Retour : Chaîne de caractères, à priori en UTF-8. * * * * Remarques : - * * * ******************************************************************************/ const char *g_string_symbol_get_utf8(const GStrSymbol *symbol) { const char *result; /* Données à retourner */ const mrange_t *range; /* Couverture du symbole */ vmpa2t pos; /* Tête de lecture modifiable */ phys_t length; /* Taille de la chaîne */ if (symbol->has_content) { range = g_binary_symbol_get_range(G_BIN_SYMBOL(symbol)); copy_vmpa(&pos, get_mrange_addr(range)); length = get_mrange_length(range); result = (const char *)g_binary_content_get_raw_access(symbol->content, &pos, length); } else result = symbol->string; return result; } /****************************************************************************** * * * Paramètres : symbol = chaîne de caractères à consulter. * * format = informations chargées à consulter. * * * * Description : Construit une désignation pour chaîne de caractères. * * * * Retour : Bilan de l'opération de mise en place. * * * * Remarques : - * * * ******************************************************************************/ bool g_string_symbol_build_label(GStrSymbol *symbol, GBinFormat *format) { const char *base; /* Contenu complet et original */ size_t length; /* Taille de la chaîne */ size_t allocated; /* Taille réservée */ char *label; /* Etiquette à constituer */ size_t cur; /* Point d'écriture courant */ unsigned int wc; /* Nombre de mots rencontrés */ size_t i; /* Boucle de parcours #1 */ char *iter; /* Boucle de parcours #2 */ gunichar c; /* Caractère unicode */ gchar *converted; /* Caractère converti */ glong size; /* Taille du caractère */ bool empty; /* Base de l'étiquette vide ? */ GBinSymbol *found; /* Symbole similaire trouvé */ const mrange_t *range; /* Couverture du symbole */ vmpa2t pos; /* Tête de lecture modifiable */ VMPA_BUFFER(last_sfx); /* Dernier suffixe à intégrer */ /* Base de décision */ base = g_string_symbol_get_utf8(symbol); if (base == NULL) return false; length = strlen(base); /* Phase de constitution */ allocated = length + 5 + VMPA_MAX_LEN + 1; label = (char *)malloc(allocated * sizeof(char)); cur = 0; wc = 0; /** * Version simple et rapide. */ if (symbol->encoding == SET_ASCII || g_str_is_ascii(base)) { for (i = 0; i < length; i++) { if (isalnum(base[i])) label[cur++] = tolower(base[i]); else if (cur > 0) { if (label[cur - 1] != '_') wc++; if (wc == 3) break; if (label[cur - 1] != '_') label[cur++] = '_'; } } } /** * Version complète. */ else { for (iter = g_utf8_offset_to_pointer(base, 0); iter != NULL; iter = g_utf8_find_next_char(iter, NULL)) { c = g_utf8_get_char_validated(iter, -1); /** * Si le caractère n'est pas valide (chaîne chiffrée ?)... */ if (c == (gunichar)-1 || c == (gunichar)-2) break; if (c == '\0') break; else if (g_unichar_isalnum(c)) { c = g_unichar_tolower(c); converted = g_ucs4_to_utf8(&c, 1, NULL, &size, NULL); label = ensure_allocation_size(label, &allocated, cur + size); memcpy(label + cur, converted, size); g_free(converted); cur += size; } else if (cur > 0) { if (label[cur - 1] != '_') wc++; if (wc == 3) break; if (label[cur - 1] != '_') { label = ensure_allocation_size(label, &allocated, cur + 1); label[cur++] = '_'; } } } } empty = (cur == 0); if (!empty && label[cur - 1] != '_') { label = ensure_allocation_size(label, &allocated, cur + 1); label[cur++] = '_'; } label = ensure_allocation_size(label, &allocated, cur + 4); strcpy(label + cur, "str"); cur += 3; /* Détermination du suffixe suffisant */ found = NULL; if (empty || g_binary_format_find_symbol_by_label(format, label, &found)) { if (found != NULL) g_object_unref(G_OBJECT(found)); if (label[cur - 1] != '_') { label = ensure_allocation_size(label, &allocated, cur + 1); label[cur++] = '_'; } range = g_binary_symbol_get_range(G_BIN_SYMBOL(symbol)); copy_vmpa(&pos, get_mrange_addr(range)); assert(has_phys_addr(&pos) || has_virt_addr(&pos)); if (has_virt_addr(&pos)) vmpa2_virt_to_string(&pos, MDS_UNDEFINED, last_sfx, NULL); else vmpa2_phys_to_string(&pos, MDS_UNDEFINED, last_sfx, NULL); label = ensure_allocation_size(label, &allocated, cur + strlen(last_sfx) + 1); strcpy(label + cur, last_sfx); } /* Application */ g_binary_symbol_set_alt_label(G_BIN_SYMBOL(symbol), label); free(label); return true; }