/* Chrysalide - Outil d'analyse de fichiers binaires * build.c - collecte des informations à enregistrer * * Copyright (C) 2009-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 "build.h" #include #include #include #include #include /* ----------------------------- GESTION DES ETIQUETTES ----------------------------- */ /* Empreinte d'une étiquette */ typedef struct _govm_label { char *name; /* Désignation humaine */ uint16_t offset; /* Position dans le code */ uint16_t *references; /* Emplacement d'utilisations */ size_t ref_count; /* Quantité d'emplacements */ } govm_label; #define INVALID_OFFSET 0xffff /* Met en place une mémoire destinée à une étiquette. */ static govm_label *create_govm_label(const char *); /* Libère la mémoire occupée par une étiquette. */ static void delete_govm_label(govm_label *); /* Recherche une étiquette correspondant à un nom donné. */ static govm_label *find_govm_label_in_list(govm_label **, size_t, const char *); /* Inscrit un nouvel emplacement à modifier après coup. */ static void attach_new_ref_to_govm_label(govm_label *, uint16_t); /* Met à jour tous les détournements de flot liés à l'étiquette. */ static bool resolve_all_refs_of_govm_label(const govm_label *, uint16_t *, govm_info *); /* -------------------------- PROCEDURES POUR L'ASSEMBLAGE -------------------------- */ /* Regroupement des informations à enregistrer */ struct _govm_info { bool little; /* Architecture choisie */ uint16_t csize; /* Taille du code */ uint16_t dsize; /* Taille des données */ uint16_t isize; /* ??? */ uint16_t bsize; /* ??? */ uint16_t start; /* Position de départ */ bin_t *code; /* Code binaire */ size_t allocated; /* Taille allouée en mémoire */ govm_label **labels; /* Nombre d'étiquettes utiles */ size_t labels_count; /* Quantité de ces étiquettes */ bool warn; /* Affichage d'avertissements */ }; #define ALLOC_CHUCK 20 /* Ajoute une instruction aux informations à enregistrer. */ static bool add_govm_instruction_code(govm_info *, bin_t); /* Inscrit une nouvelle étiquette vierge. */ static govm_label *insert_new_govm_label(govm_info *, const char *); /* ---------------------------------------------------------------------------------- */ /* GESTION DES ETIQUETTES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : name = désignation humaine de l'étiquette. * * * * Description : Met en place une mémoire destinée à une étiquette. * * * * Retour : Structure de représentation initialisée. * * * * Remarques : - * * * ******************************************************************************/ static govm_label *create_govm_label(const char *name) { govm_label *result; /* Structure à retourner */ size_t len; /* Taille du nom pour analyse */ result = (govm_label *)calloc(1, sizeof(govm_label)); result->name = strdup(name); len = strlen(name); if (name[len - 1] == ':') result->name[len - 1] = '\0'; result->offset = INVALID_OFFSET; return result; } /****************************************************************************** * * * Paramètres : label = étiquette à supprimer de la mémoire. * * * * Description : Libère la mémoire occupée par une étiquette. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void delete_govm_label(govm_label *label) { free(label->name); if (label->references != NULL) free(label->references); free(label); } /****************************************************************************** * * * Paramètres : list = liste d'éléments à parcourir. * * count = taille de la liste. * * name = nom de l'étiquette à chercher. * * * * Description : Recherche une étiquette correspondant à un nom donné. * * * * Retour : Adresse de l'étiquette trouvée ou NULL. * * * * Remarques : - * * * ******************************************************************************/ static govm_label *find_govm_label_in_list(govm_label **list, size_t count, const char *name) { govm_label *result; /* Résultat à renvoyer */ size_t len; /* Longueur de comparaison */ size_t i; /* Boucle de parcours */ result = NULL; len = strlen(name); if (name[len - 1] == ':') len--; for (i = 0; i < count && result == NULL; i++) { if (list[i]->name == NULL) continue; if (strncmp(list[i]->name, name, len) == 0) result = list[i]; } return result; } /****************************************************************************** * * * Paramètres : label = élément à compléter. * * count = taille de la liste. * * name = nom de l'étiquette à chercher. * * * * Description : Inscrit un nouvel emplacement à modifier après coup. * * * * Retour : Adresse de l'étiquette trouvée ou NULL. * * * * Remarques : - * * * ******************************************************************************/ static void attach_new_ref_to_govm_label(govm_label *label, uint16_t ref) { label->references = (uint16_t *)realloc(label->references, ++label->ref_count * sizeof(uint16_t)); label->references[label->ref_count - 1] = ref; } /****************************************************************************** * * * Paramètres : label = élément à manipuler. * * pc = emplacement de la tête d'écriture à modifier. * * info = informations globales pour l'ajout. * * * * Description : Met à jour tous les détournements de flot liés à l'étiquette.* * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool resolve_all_refs_of_govm_label(const govm_label *label, uint16_t *pc, govm_info *info) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ result = true; if (label->offset == INVALID_OFFSET) { fprintf(stderr, "Label '%s' used, but never defined !\n", label->name); return false; } if (label->ref_count == 0 && info->warn && strcmp(label->name, "start") != 0) fprintf(stderr, "Label '%s' defined, but never used !\n", label->name); for (i = 0; i < label->ref_count && result; i++) { *pc = label->references[i]; result = encode_govm_number(info, label->offset); } return result; } /* ---------------------------------------------------------------------------------- */ /* PROCEDURES POUR L'ASSEMBLAGE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : little = architecture en petit boutisme ? * * warn = affichage des avertissements ? * * * * Description : Met en place une future collecte d'informations. * * * * Retour : Ensemble d'informations initialisées. * * * * Remarques : - * * * ******************************************************************************/ govm_info *create_govm_info(bool little, bool warn) { govm_info *result; /* Structure à retourner */ result = (govm_info *)calloc(1, sizeof(govm_info)); result->little = little; result->warn = warn; return result; } /****************************************************************************** * * * Paramètres : info = informations à libérer de la mémoire. * * * * Description : Supprime de la mémoire toutes les informations collectées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_govm_info(govm_info *info) { size_t i; /* Boucle de parcours */ if (info->allocated > 0) free(info->code); if (info->labels_count > 0) { for (i = 0; i < info->labels_count; i++) delete_govm_label(info->labels[i]); free(info->labels); } free(info); } bool write_u16(int fd, uint16_t val); bool write_u16(int fd, uint16_t val) { ssize_t len; /* Quantité de données écrites */ len = write(fd, &val, 2); return (len == 2); } /****************************************************************************** * * * Paramètres : info = ensemble à mettre à jour. * * value = valeur à ajouter à la section de code. * * * * Description : Ajoute une instruction aux informations à enregistrer. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool add_govm_instruction_code(govm_info *info, bin_t value) { bool even; /* Zone pour le demi-octet */ if (info->csize / 2 == info->allocated) { info->allocated += ALLOC_CHUCK; info->code = (bin_t *)realloc(info->code, info->allocated * sizeof(bin_t)); memset(&info->code[info->csize / 2], 0, ALLOC_CHUCK * sizeof(bin_t)); } even = (info->csize % 2 == 0); if (info->little) even = !even; if (even) info->code[info->csize / 2] |= (value & 0x0f) << 4; else info->code[info->csize / 2] |= (value & 0x0f); info->csize++; return true; } /****************************************************************************** * * * Paramètres : info = ensemble à mettre à jour. * * id = identifiant de l'instruction à exporter. * * * * Description : Ajoute une instruction aux informations à enregistrer. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool encode_govm_instruction(govm_info *info, GoVMOpcodes id) { bool result; /* Bilan à renvoyer */ bin_t opcode; /* Octet d'encodage à écrire */ opcode = get_govm_instruction_opcode(id); if (opcode >= 0x08) { result = add_govm_instruction_code(info, (opcode & 0x0f) | 0x08); result &= add_govm_instruction_code(info, opcode >> 3); } else result = add_govm_instruction_code(info, opcode); return result; } /****************************************************************************** * * * Paramètres : info = ensemble à mettre à jour. * * value = valeur à placer directement dans le code. * * * * Description : Ajoute une valeur entière dans le code même. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool encode_govm_number(govm_info *info, uint16_t value) { bool result; /* Bilan à renvoyer */ size_t i; /* Boucle de parcours */ result = true; if (info->little) for (i = 0; i < 16 && result; i += 4) result = add_govm_instruction_code(info, (value >> i) & 0x0f); else for (i = 16; i > 0 && result; i -= 4) result = add_govm_instruction_code(info, (value >> (i - 4)) & 0x0f); return result; } /****************************************************************************** * * * Paramètres : info = ensemble à mettre à jour. * * name = désignation humaine de la nouvelle étiquette. * * * * Description : Inscrit une nouvelle étiquette vierge. * * * * Retour : Adresse de l'étiquette créée. * * * * Remarques : - * * * ******************************************************************************/ static govm_label *insert_new_govm_label(govm_info *info, const char *name) { govm_label *result; /* Etiquette à retourner */ result = create_govm_label(name); info->labels = (govm_label **)realloc(info->labels, ++info->labels_count * sizeof(govm_label *)); info->labels[info->labels_count - 1] = result; return result; } /****************************************************************************** * * * Paramètres : info = ensemble à mettre à jour. * * name = désignation humaine de la nouvelle étiquette. * * * * Description : Enregistre un nouvel emplacement d'étiquette. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool register_govm_label(govm_info *info, const char *name) { govm_label *label; /* Etiquette à créer */ label = find_govm_label_in_list(info->labels, info->labels_count, name); if (label == NULL) label = insert_new_govm_label(info, name); if (label->offset != INVALID_OFFSET) { fprintf(stderr, "Label '%s' already defined !", label->name); return false; } label->offset = info->csize; return true; } /****************************************************************************** * * * Paramètres : info = ensemble à mettre à jour. * * id = identifiant de l'instruction à utiliser. * * name = désignation humaine de l'étiquette visée. * * * * Description : Exécute un détournement de flot via une étiquette. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool encode_reference_to_govm_label(govm_info *info, GoVMOpcodes id, const char *name) { govm_label *label; /* Etiquette à modifier */ if (!encode_govm_instruction(info, GOP_LI)) return false; label = find_govm_label_in_list(info->labels, info->labels_count, name); if (label == NULL) label = insert_new_govm_label(info, name); attach_new_ref_to_govm_label(label, info->csize); if (!encode_govm_number(info, 0x0000)) return false; return encode_govm_instruction(info, id); } /****************************************************************************** * * * Paramètres : info = ensemble à initialiser. * * fd = flux ouvert en écriture. * * * * Description : Procède à l'enregistrement d'un shellcode pour GoVM. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool write_govm_info(govm_info *info, int fd) { bool result; /* Bilan à retourner */ uint16_t tmp; /* Sauvegarde de la quantité */ size_t i; /* Boucle de parcours */ ssize_t len; /* Quantité de données écrites */ uint16_t expected; /* Quantité de données à écrire*/ govm_label *label; /* Etiquette pour le début */ result = true; tmp = info->csize; for (i = 0; i < info->labels_count && result; i++) result = resolve_all_refs_of_govm_label(info->labels[i], &info->csize, info); info->csize = tmp; if (!result) return false; len = write(fd, "GOVM", 4); result = (len != 4); if (info->little) len = write(fd, "\x10", 1); else len = write(fd, "\x11", 1); result = (len != 1); /* Egalisation */ if (info->csize % 2 != 0) { encode_govm_instruction(info, GOP_LI); encode_govm_number(info, 0xffff); encode_govm_instruction(info, GOP_POP); } expected = (info->csize % 2 == 0 ? info->csize / 2 : info->csize / 2 + 1); expected *= sizeof(bin_t); result &= write_u16(fd, expected); result &= write_u16(fd, info->dsize); result &= write_u16(fd, info->isize); result &= write_u16(fd, info->bsize); label = find_govm_label_in_list(info->labels, info->labels_count, "start"); if (label != NULL) info->start = label->offset; result &= write_u16(fd, info->start); len = write(fd, info->code, expected); result = (len != expected); return result; }