summaryrefslogtreecommitdiff
path: root/plugins/theseus
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/theseus')
-rw-r--r--plugins/theseus/Makefile.am14
-rw-r--r--plugins/theseus/theseus.c620
-rw-r--r--plugins/theseus/theseus.h49
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 */