diff options
Diffstat (limited to 'plugins/theseus')
-rw-r--r-- | plugins/theseus/Makefile.am | 14 | ||||
-rw-r--r-- | plugins/theseus/theseus.c | 620 | ||||
-rw-r--r-- | plugins/theseus/theseus.h | 49 |
3 files changed, 683 insertions, 0 deletions
diff --git a/plugins/theseus/Makefile.am b/plugins/theseus/Makefile.am new file mode 100644 index 0000000..8040bb4 --- /dev/null +++ b/plugins/theseus/Makefile.am @@ -0,0 +1,14 @@ + +lib_LTLIBRARIES = libtheseus.la + +libtheseus_la_SOURCES = \ + theseus.h theseus.c + +libtheseus_la_CFLAGS = $(AM_CFLAGS) + + +INCLUDES = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I../../src + +AM_CPPFLAGS = + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/theseus/theseus.c b/plugins/theseus/theseus.c new file mode 100644 index 0000000..aec5353 --- /dev/null +++ b/plugins/theseus/theseus.c @@ -0,0 +1,620 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * theseus.c - décompilation en fonction du flot d'exécution + * + * Copyright (C) 2010 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA 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. + * + * OpenIDA 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 "theseus.h" + + +#include <analysis/exporter.h> +#include <analysis/line_code.h> +#include <arch/artificial.h> + + +/* Traite en premier lieu les adresses marquées "impératives". */ +static bool register_white_list(GOpenidaBinary *); + +/* Indique si une ligne peut faire l'objet d'un nouveau suivi. */ +static bool can_line_be_followed(const GRenderingLine *); + +/* Indique si une ligne a déjà été traitée lors d'un suivi. */ +static bool can_line_be_processed(const GRenderingLine *); + +/* Marque une ligne comme ayant été traitée. */ +static void mark_line_as_done(GRenderingLine *, bool); + +/* Suit le flot d'exécution à partir d'un point donné. */ +static bool follow_flow_from_line(GOpenidaBinary *, vmpa_t); + +/* Désassemble une nouvelle instruction à partir d'une adresse. */ +static GRenderingLine *disassemble_target_address(GOpenidaBinary *, GRenderingLine *, vmpa_t); + +/* Insère dans le flux existant les nouvelles lignes crées. */ +static bool insert_new_lines_into_flow(GOpenidaBinary *, GRenderingLine *, GRenderingLine *); + + + + + +/* +mov edx, 0x80480fb +call [edx] +mov edx, 0x80480fb +add edx, 0x8 +call [edx] +mov edx, 0x80480fb +add edx, 0x10 +call [edx] +mov edx, 0x80480fb +add edx, 0xc +call [edx] +mov edx, 0x80480fb +add edx, 0x14 +call [edx] +mov edx, 0x80480fb +add edx, 0x4 +call [edx] +*/ + + +static const vmpa_t _white_list[] = { + 0x80480fbull, + 0x8048103ull, + 0x804810bull, + 0x8048107ull, + 0x804810full, + 0x80480ffull +}; + +static const size_t _white_list_count = 6; + + + + +/****************************************************************************** +* * +* Paramètres : ref = espace de référencement global. * +* * +* Description : Initialise le greffon pour les bornes de routine. * +* * +* Retour : true. * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool init_plugin(GObject *ref) +{ + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit une indication sur le type d'opération(s) menée(s). * +* * +* Retour : Description d'une action. * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT PluginAction get_plugin_action(void) +{ + return PGA_CODE_PROCESS; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = représentation binaire à traiter. * +* action = action attendue. * +* * +* Description : Exécute une action définie sur un binaire chargé. * +* * +* Retour : true si une action a été menée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool execute_action_on_binary(GOpenidaBinary *binary, PluginAction action) +{ + bool result; /* Bilan à retourner */ + GRenderingLine *lines; /* Lignes désassemblées */ + GExeFormat *format; /* Format du binaire traité */ + vmpa_t start; /* Point de départ de l'action */ + + + + GRenderingOptions *options; + GRenderingLine *iter; + + + lines = g_openida_binary_get_lines(binary); + + + + + format = g_openida_binary_get_format(binary); + + start = g_exe_format_get_entry_point(format); + + result = register_white_list(binary); + + result &= follow_flow_from_line(binary, start); + + + //follow_flow_from_line(binary, 0x0804810bull); + + + + + + options = g_openida_binary_get_options(binary); + + for (iter = lines; iter != NULL; iter = g_rendering_line_get_next_iter(lines, iter, NULL)) + { + + printf(" >>>>>> %c%c ", + g_object_get_data(G_OBJECT(iter), "theseus_white") != NULL ? '!' : ' ', + g_object_get_data(G_OBJECT(iter), "theseus_done") != NULL ? '*' : ' '); + g_content_exporter_add_text(G_CONTENT_EXPORTER(iter), options, 0/*MRD_BLOCK*/, stdout); + fflush(stdout); + printf("\n"); + + + } + + + + //exit(-1); + + + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = représentation binaire à traiter. * +* * +* Description : Traite en premier lieu les adresses marquées "impératives". * +* * +* Retour : true si le déroulement s'est bien effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool register_white_list(GOpenidaBinary *binary) +{ + bool result; /* Bilan à retourner */ + GRenderingLine *lines; /* Lignes désassemblées */ + size_t i; /* Boucle de parcours */ + GRenderingLine *target; /* Ligne à transformer ? */ + GRenderingLine *last; /* Nouvelle ligne principale */ + GRenderingLine *new; /* Nouvelles lignes de rendu */ + + result = true; + + lines = g_openida_binary_get_lines(binary); + + for (i = 0; i < _white_list_count && result; i++) + { + target = g_rendering_line_find_by_address(lines, NULL, _white_list[i]); + target = g_rendering_line_loop_for_code(target, NULL); + + new = disassemble_target_address(binary, target, _white_list[i]); + + last = g_rendering_line_get_last_iter(new, NULL); + mark_line_as_done(last, true); + + result = insert_new_lines_into_flow(binary, target, new); + + result &= follow_flow_from_line(binary, _white_list[i]); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne de rendu à analyser. * +* * +* Description : Indique si une ligne peut faire l'objet d'un nouveau suivi. * +* * +* Retour : true si le suivi peut continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool can_line_be_followed(const GRenderingLine *line) +{ + bool result; /* Bilan d'analyse à renvoyer */ + + result = true; + + if (g_object_get_data(G_OBJECT(line), "theseus_done") != NULL) + result = (g_object_get_data(G_OBJECT(line), "theseus_white") != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne de rendu à analyser. * +* * +* Description : Indique si une ligne a déjà été traitée lors d'un suivi. * +* * +* Retour : true si le suivi peut continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool can_line_be_processed(const GRenderingLine *line) +{ + return (g_object_get_data(G_OBJECT(line), "theseus_done") == NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne de rendu à traiter. * +* white = type de marquage à apposer (liste blanche ou normal).* +* * +* Description : Marque une ligne comme ayant été traitée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void mark_line_as_done(GRenderingLine *line, bool white) +{ + if (white) + g_object_set_data(G_OBJECT(line), "theseus_white", line); + else + g_object_set_data(G_OBJECT(line), "theseus_done", line); + +} + + +/****************************************************************************** +* * +* Paramètres : binary = représentation binaire à traiter. * +* start = point de départ de la procédure. * +* * +* Description : Suit le flot d'exécution à partir d'un point donné. * +* * +* Retour : true si le déroulement s'est bien effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool follow_flow_from_line(GOpenidaBinary *binary, vmpa_t start) +{ + bool result; /* Bilan de opérations */ + GRenderingLine *lines; /* Lignes désassemblées */ + GRenderingLine *first; /* Première ligne à traiter */ + vmpa_t addr; /* Adresse référencée */ + GRenderingLine *new; /* Nouvelles lignes de rendu */ + GRenderingLine *iter; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction à ausculter */ + InstructionLinkType type; /* Type de référence */ + GRenderingLine *target; /* Ligne visée par la référence*/ + + lines = g_openida_binary_get_lines(binary); + + first = g_rendering_line_find_by_address(lines, NULL, start); + first = g_rendering_line_loop_for_code(first, NULL); + + if (!can_line_be_followed(first)) + return true; + + //if (start != 0x0804810bull) return true; + + printf("###################################### Passage\n"); + + /* Alignement sur le point d'entrée */ + + result = true; + + addr = get_rendering_line_address(first); + + if (addr < start) + { + new = disassemble_target_address(binary, first, start); + + result = insert_new_lines_into_flow(binary, target, new); + + first = g_rendering_line_find_by_address(lines, NULL, start); + + //return true; + + } + else g_object_set_data(G_OBJECT(first), "theseus_done", binary); + + + + + printf("Analyse :: 0x%016llx\n", get_rendering_line_address(first)); + + + + + + /* Poursuite du suivi du flot... */ + + for (iter = g_rendering_line_get_next_iter(lines, first, NULL); + iter != NULL/* && result*/; + iter = g_rendering_line_get_next_iter(lines, iter, NULL)) + { + /* On ne traite que du code ici ! */ + if (!G_IS_CODE_LINE(iter)) continue; + + /* + printf("testing... 0x%08llx => %d\n", + get_rendering_line_address(iter), + can_line_be_processed(iter)); + */ + + if (!can_line_be_processed(iter)) + break; + + instr = g_code_line_get_instruction(G_CODE_LINE(iter)); + + /* Si le code n'es pas désassemblé ! */ + if (G_IS_DB_INSTRUCTION(instr)) + { + new = disassemble_target_address(binary, iter, get_rendering_line_address(iter)); + result = insert_new_lines_into_flow(binary, iter, new); + + if (!result) + { + mark_line_as_done(iter, false); + break; + } + else + { + iter = new; + mark_line_as_done(iter, false); + + instr = g_code_line_get_instruction(G_CODE_LINE(iter)); + if (!G_IS_DB_INSTRUCTION(instr)) break; + + } + + } + else mark_line_as_done(iter, false); + + type = g_arch_instruction_get_link(instr, &addr); + + if (get_rendering_line_address(iter) == 0x0804811aull) + printf(" == got it !! ==\n"); + + + switch (type) + { + case ILT_JUMP: + case ILT_JUMP_IF_FALSE: + case ILT_JUMP_IF_TRUE: + result = follow_flow_from_line(binary, addr); + break; + + default: + break; + + } + + if (get_rendering_line_address(iter) == 0x0804811aull) + printf(" == continue ? %d\n", result); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = représentation binaire à traiter. * +* old = ligne contenant l'adresse visée à remplacer. * +* target = adresse de la nouvelle instruction à voir. * +* * +* Description : Désassemble une nouvelle instruction à partir d'une adresse. * +* * +* Retour : Nouvelle(s) ligne(s) en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GRenderingLine *disassemble_target_address(GOpenidaBinary *binary, GRenderingLine *old, vmpa_t target) +{ + GRenderingLine *result; /* Lignes en place à renvoyer */ + GExeFormat *format; /* Format du binaire fourni */ + GArchProcessor *proc; /* Architecture du binaire */ + GRenderingOptions *options; /* Options de désassemblage */ + bin_t *data; /* Données binaires chargées */ + off_t length; /* Taille du code binaire */ + vmpa_t old_addr; /* Adresse de ligne à casser */ + off_t offset; /* Position dans le contenu */ + vmpa_t i; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction décodée */ + GRenderingLine *line; /* Nouvelle ligne de rendu */ + + result = NULL; + + format = g_openida_binary_get_format(binary); + proc = get_arch_processor_from_format(format); + options = g_openida_binary_get_options(binary); + + data = g_openida_binary_get_data(binary, &length); + + old_addr = get_rendering_line_address(old); + if (!g_exe_format_translate_address_into_offset(format, old_addr, &offset)) + return NULL; + + /* Si on doit laisser sur le carreau quelques octets perdus... */ + for (i = 0; i < (target - old_addr); i++) + { + instr = g_db_instruction_new_from_data(data, &offset, length, 0/*base*/, proc); + g_arch_instruction_set_location(instr, 0/*base*/ + offset - 1, 1, old_addr + i); + + line = g_code_line_new(old_addr + i, instr, options); + g_rendering_line_add_to_lines(&result, line); + + } + + /* Décodage des instructions */ + + instr = g_arch_processor_decode_instruction(proc, data, + &offset, length, 0/*offset*/, target); + + line = g_code_line_new(target, instr, options); + g_rendering_line_add_to_lines(&result, line); + + mark_line_as_done(line, false); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = représentation binaire à traiter. * +* old = ancienne ligne, point de départ des remplacements. * +* new = nouvelle(s) ligne(s) de représentation. * +* * +* Description : Insère dans le flux existant les nouvelles lignes crées. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool insert_new_lines_into_flow(GOpenidaBinary *binary, GRenderingLine *old, GRenderingLine *new) +{ + bool result; /* Bilan de opérations */ + GExeFormat *format; /* Format du binaire fourni */ + GArchProcessor *proc; /* Architecture du binaire */ + GRenderingOptions *options; /* Options de désassemblage */ + bin_t *data; /* Données binaires chargées */ + off_t length; /* Taille du code binaire */ + GRenderingLine **root; /* Racine des lignes de rendu */ + GRenderingLine *iter; /* Boucle de parcours */ + vmpa_t start; /* Adresse de début du bloc */ + vmpa_t end; /* Adresse de fin du bloc */ + vmpa_t max; /* Adresse de fin de ligne */ + vmpa_t i; /* Boucle de parcours */ + off_t offset; /* Position dans le contenu */ + GArchInstruction *instr; /* Instruction décodée */ + GRenderingLine *line; /* Nouvelle ligne de rendu */ + GRenderingLine *last; /* Dernière ligne à vérifier */ + + format = g_openida_binary_get_format(binary); + proc = get_arch_processor_from_format(format); + options = g_openida_binary_get_options(binary); + + data = g_openida_binary_get_data(binary, &length); + + /* Etendue du bloc de remplacement */ + + iter = g_rendering_line_get_last_iter(new, NULL); + + start = get_rendering_line_address(new); + + end = get_rendering_line_address(iter); + end += get_rendering_line_length(iter) - 1; + + /* Bourrage nécessaire ? */ + + root = g_openida_binary_get_lines_root(binary); + + iter = g_rendering_line_find_by_address(*root, NULL, end); + + max = get_rendering_line_address(iter); + max += get_rendering_line_length(iter); + + for (i = end + 1; i < max; i++) + { + if (!g_exe_format_translate_address_into_offset(format, i, &offset)) + /** + * Comme les adresses proviennent à l'origine de partie valide, + * on considère que l'appel est toujours un succès. + * Cela permet d'avoir deux bilan possible : procédure bien déroulée, + * ou bien remplacement impossible pour cause de place déjà prise. + */ + /*return false*/; + + instr = g_db_instruction_new_from_data(data, &offset, length, 0/*base*/, proc); + g_arch_instruction_set_location(instr, 0/*base*/ + offset - 1, 1, i); + + line = g_code_line_new(i, instr, options); + g_rendering_line_add_to_lines(&new, line); + + } + + /* S'assure qu'on ne touche à rien de sacré */ + + result = true; + + last = g_rendering_line_find_by_address(*root, NULL, end); + + for (iter = g_rendering_line_find_by_address(*root, NULL, start); + iter != NULL && result; + iter = g_rendering_line_get_next_iter(*root, iter, last)) + { + result = can_line_be_processed(iter); + } + + /* Remplacement en bonne et due forme */ + + if (result) + { + g_rendering_line_remove_range(root, start, end); + g_rendering_line_insert_lines(root, &new); + } + + return result; + +} diff --git a/plugins/theseus/theseus.h b/plugins/theseus/theseus.h new file mode 100644 index 0000000..2fa4ac1 --- /dev/null +++ b/plugins/theseus/theseus.h @@ -0,0 +1,49 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * theseus.h - prototypes pour la décompilation en fonction du flot d'exécution + * + * Copyright (C) 2010 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA 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. + * + * OpenIDA 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/>. + */ + + +#ifndef _PLUGINS_THESEUS_THESEUS_H +#define _PLUGINS_THESEUS_THESEUS_H + + +#include <glib-object.h> +#include <gmodule.h> +#include <stdbool.h> + + +#include <analysis/binary.h> +#include <plugins/plugin-def.h> + + + +/* Initialise le greffon pour les bornes de routine. */ +G_MODULE_EXPORT bool init_plugin(GObject *); + +/* Fournit une indication sur le type d'opération(s) menée(s). */ +G_MODULE_EXPORT PluginAction get_plugin_action(void); + +/* Exécute une action définie sur un binaire chargé. */ +G_MODULE_EXPORT bool execute_action_on_binary(GOpenidaBinary *, PluginAction); + + + +#endif /* _PLUGINS_THESEUS_THESEUS_H */ |