/* Chrysalide - Outil d'analyse de fichiers binaires * manager.c - désassemblage sous condition * * 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 Chrysalide. If not, see . */ #include "manager.h" #include #include #include #include "../helpers.h" /* Elément d'une condition décodée */ typedef struct _def_cond { char *field; /* Désignation du champ */ DisassCondOp op; /* Opération de comparaison */ char *value; /* Désignation de la valeur */ char *lower; /* Version minuscule */ } def_cond; /* Ligne de condition(s) */ typedef struct _cond_line { def_cond *conditions; /* Conditions à vérifier */ size_t count; /* Taille de cette liste */ DisassCondGroup group; /* Type du groupe */ } cond_line; /* Représentation de l'ensemble de conditions préalables */ struct _disass_assert { cond_line *lines; /* Lignes de conditions */ size_t count; /* Taille de cette liste */ }; /* Définit le masque correspondant à une valeur booléenne. */ static char *get_disass_assert_mask(const char *); /* Définit la valeur correspondant à une valeur booléenne. */ static char *get_disass_assert_value(const char *); /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouveau gestionnaire de conditions de désassemblage. * * * * Retour : Nouvelle structure prête à emploi. * * * * Remarques : - * * * ******************************************************************************/ disass_assert *create_disass_assert(void) { disass_assert *result; /* Définition vierge à renvoyer*/ result = (disass_assert *)calloc(1, sizeof(disass_assert)); return result; } /****************************************************************************** * * * Paramètres : dassert = gestionnaire d'un ensemble de conditions à libérer.* * * * Description : Supprime de la mémoire un gestionnaire de conditions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_disass_assert(disass_assert *dassert) { size_t i; /* Boucle de parcours #1 */ cond_line *line; /* Ligne à compléter */ size_t j; /* Boucle de parcours #2 */ for (i = 0; i < dassert->count; i++) { line = &dassert->lines[i]; for (j = 0; j < line->count; j++) { free(line->conditions[j].field); free(line->conditions[j].value); free(line->conditions[j].lower); } if (line->conditions != NULL) free(line->conditions); } if (dassert->lines != NULL) free(dassert->lines); free(dassert); } /****************************************************************************** * * * Paramètres : dassert = gestionnaire de conditions à consulter. * * group = type du groupe de conditions attendues. * * field = champ de bits à prendre en compte. * * op = type d'opération impliquée. * * value = valeur soumise à condition. * * * * Description : Initie une nouvelle condition à vérifier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void register_disass_assert(disass_assert *dassert, DisassCondGroup group, char *field, DisassCondOp op, char *value) { cond_line *new; /* Nouvelle ligne de conditions*/ dassert->lines = (cond_line *)realloc(dassert->lines, ++dassert->count * sizeof(cond_line)); new = &dassert->lines[dassert->count - 1]; new->conditions = NULL; new->count = 0; new->group = group; extend_disass_assert(dassert, field, op, value); } /****************************************************************************** * * * Paramètres : dassert = gestionnaire de conditions à consulter. * * field = champ de bits à prendre en compte. * * op = type d'opération impliquée. * * value = valeur soumise à condition. * * * * Description : Enregistre une nouvelle condition à vérifier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void extend_disass_assert(disass_assert *dassert, char *field, DisassCondOp op, char *value) { cond_line *line; /* Ligne à compléter */ def_cond *new; /* Nouvelle définition */ assert(dassert->count > 0); line = &dassert->lines[dassert->count - 1]; line->conditions = (def_cond *)realloc(line->conditions, ++line->count * sizeof(def_cond)); new = &line->conditions[line->count - 1]; new->field = field; new->op = op; new->value = value; new->lower = strdup(field); make_string_lower(new->lower); } /****************************************************************************** * * * Paramètres : dassert = gestionnaire de conditions à consulter. * * * * Description : Indique la présence de conditions à vérifier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ bool is_disass_assert_empty(const disass_assert *dassert) { bool result; /* Bilan à retourner */ result = (dassert->count == 0); return result; } /****************************************************************************** * * * Paramètres : dassert = gestionnaire d'un ensemble de conditions à marquer.* * bits = gestionnaire des bits d'encodage. * * * * Description : Marque les éléments de condition effectivement utilisés. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool mark_disass_assert(const disass_assert *dassert, const coding_bits *bits) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours #1 */ cond_line *line; /* Ligne de condition(s) */ size_t j; /* Boucle de parcours #2 */ def_cond *cond; /* Condition à marquer */ raw_bitfield *rf; /* Champ de bits à marquer */ result = true; for (i = 0; i < dassert->count && result; i++) { line = &dassert->lines[i]; for (j = 0; j < line->count && result; j++) { cond = &line->conditions[j]; rf = find_named_field_in_bits(bits, cond->lower); if (rf == NULL) { fprintf(stderr, "Unknown bitfield '%s' for condition!\n", cond->field); result = false; } else mark_raw_bitfield_as_used(rf); } } return result; } /****************************************************************************** * * * Paramètres : dassert = gestionnaire d'un ensemble de conditions à définir.* * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * * * Description : Définit les éléments de condition à appliquer. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool define_disass_assert(const disass_assert *dassert, int fd, const coding_bits *bits) { size_t i; /* Boucle de parcours #1 */ cond_line *line; /* Ligne de condition(s) */ size_t j; /* Boucle de parcours #2 */ def_cond *cond; /* Condition à marquer */ raw_bitfield *rf; /* Champ de bits à marquer */ char *mask; /* Eventuel masque à appliquer */ char *expected; /* Valeur attendue */ for (i = 0; i < dassert->count; i++) { line = &dassert->lines[i]; if (i > 0) dprintf(fd, " && "); if (dassert->count > 1 && line->count > 1) dprintf(fd, "("); for (j = 0; j < line->count; j++) { cond = &line->conditions[j]; rf = find_named_field_in_bits(bits, cond->lower); assert(rf != NULL); if (j > 0) switch (line->group) { case DCG_UNIQ: assert(false); break; case DCG_AND: dprintf(fd, " && "); break; case DCG_OR: dprintf(fd, " || "); break; } mask = get_disass_assert_mask(cond->value); if (mask == NULL) write_raw_bitfield(rf, fd); else { dprintf(fd, "("); write_raw_bitfield(rf, fd); dprintf(fd, " & %s)", mask); free(mask); } switch (cond->op) { case DCO_EQ: dprintf(fd, " == "); break; case DCO_NE: dprintf(fd, " != "); break; } expected = get_disass_assert_value(cond->value); dprintf(fd, "%s", expected); free(expected); } if (dassert->count > 1 && line->count > 1) dprintf(fd, ")"); } return true; } /****************************************************************************** * * * Paramètres : value = valeur booléenne à écrire. * * * * Description : Définit le masque correspondant à une valeur booléenne. * * * * Retour : Masque à appliquer (et libérer) ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ static char *get_disass_assert_mask(const char *value) { char *result; /* Masque à renvoyer */ char *iter; /* Boucle de parcours */ if (strchr(value, 'x') == NULL) result = NULL; else { result = strdup(value); for (iter = result; *iter != '\0'; iter++) switch (*iter) { case '0': case '1': *iter = '1'; break; case 'x': *iter = '0'; break; default: assert(false); break; } } return result; } /****************************************************************************** * * * Paramètres : value = valeur booléenne à écrire. * * * * Description : Définit la valeur correspondant à une valeur booléenne. * * * * Retour : Valeur à comparer et libérer. * * * * Remarques : - * * * ******************************************************************************/ static char *get_disass_assert_value(const char *value) { char *result; /* Masque à renvoyer */ char *iter; /* Boucle de parcours */ result = strdup(value); if (strchr(value, 'x') != NULL) for (iter = result; *iter != '\0'; iter++) switch (*iter) { case '0': case '1': break; case 'x': *iter = '0'; break; default: assert(false); break; } return result; }