/* Chrysalide - Outil d'analyse de fichiers binaires * disassembler.c - encadrement des phases de désassemblage * * Copyright (C) 2010-2014 Cyrille Bagard * * This file is part of Chrysalide. * * 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 . */ #include "disassembler.h" #include #include #include #include #include "fetch.h" #include "limit.h" #include "links.h" #include "loop.h" #include "macro.h" #include "output.h" #include "rank.h" #include "../../decomp/lang/asm.h" #include "../../format/format.h" #include "../../glibext/delayed-int.h" #include "../../gui/panels/log.h" #include "../../plugins/pglist.h" /* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ /* Ensembles binaires à désassembler (instance) */ struct _GDelayedDisassembly { GDelayedWork parent; /* A laisser en premier */ GLoadedBinary *binary; /* Destinataire final */ GExeFormat *format; /* Format du binaire représenté*/ GArchInstruction **instrs; /* Instructions résultantes */ GCodeBuffer *buffer; /* Tampon pour le rendu */ }; /* Ensembles binaires à désassembler (classe) */ struct _GDelayedDisassemblyClass { GDelayedWorkClass parent; /* A laisser en premier */ }; /* Initialise la classe des tâches de désassemblage différé. */ static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *); /* Initialise une tâche de désassemblage différé. */ static void g_delayed_disassembly_init(GDelayedDisassembly *); /* Crée une tâche de désassemblage différé. */ static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *, GArchInstruction **, GCodeBuffer *); /* Assure le désassemblage en différé. */ static void g_delayed_disassembly_process(GDelayedDisassembly *, GtkExtStatusBar *); /* -------------------------- GESTION GLOBALE DE PROCEDURE -------------------------- */ /* Construit la description d'introduction du désassemblage. */ static void build_disass_prologue(GCodeBuffer *, const char *, const char *); /* ---------------------------------------------------------------------------------- */ /* DESASSEMBLAGE DE BINAIRE DIFFERE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour les tâches de désassemblage différé. */ G_DEFINE_TYPE(GDelayedDisassembly, g_delayed_disassembly, G_TYPE_DELAYED_WORK); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des tâches de désassemblage différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *klass) { GDelayedWorkClass *work; /* Version en classe parente */ work = G_DELAYED_WORK_CLASS(klass); work->run = (run_task_fc)g_delayed_disassembly_process; } /****************************************************************************** * * * Paramètres : disass = instance à initialiser. * * * * Description : Initialise une tâche de désassemblage différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_disassembly_init(GDelayedDisassembly *disass) { } /****************************************************************************** * * * Paramètres : binary = binaire chargé en attente des résultats. * * format = format du binaire représenté. * * instrs = emplacement pour la liste d'instructions. * * buffer = tampon de sortie pour les instructions. * * * * Description : Crée une tâche de désassemblage différé. * * * * Retour : Tâche créée. * * * * Remarques : - * * * ******************************************************************************/ static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *binary, GArchInstruction **instrs, GCodeBuffer *buffer) { GDelayedDisassembly *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_DELAYED_DISASSEMBLY, NULL); result->binary = binary; result->format = g_loaded_binary_get_format(binary); result->instrs = instrs; result->buffer = buffer; return result; } /****************************************************************************** * * * Paramètres : disass = analyse à mener. * * statusbar = barre de statut à tenir informée. * * * * Description : Assure le désassemblage en différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar) { wgroup_id_t gid; /* Identifiant pour les tâches */ //GBinFormat *format; /* Format du fichier binaire */ GArchProcessor *proc; /* Architecture du binaire */ unsigned int valid; /* Instructions traduites */ unsigned int db; /* Instructions non décodées */ unsigned int valid_sum; /* Instructions traduites */ unsigned int instr_sum; /* Instructions totales */ size_t i; /* Boucle de parcours */ GBinRoutine **routines; /* Liste des routines trouvées */ size_t routines_count; /* Nombre de ces routines */ bstatus_id_t id; /* Identifiant de statut */ //GArchProcessor *proc; /* Architecture du binaire */ gid = g_work_queue_define_work_group(get_work_queue()); //format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); proc = g_loaded_binary_get_processor(disass->binary); routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count); /* Première étape */ //id = gtk_extended_status_bar_push(statusbar, _("Disassembling..."), true); process_disassembly_event(PGA_DISASSEMBLY_STARTED, disass->binary); *disass->instrs = disassemble_binary_content(disass->binary, gid, statusbar); g_arch_processor_set_disassembled_instructions(proc, *disass->instrs); // plugins ////////////////////////// process_disassembly_event(PGA_DISASSEMBLY_RAW, disass->binary); /* *disass->instrs = disassemble_binary_parts(disass->binary, disass->parts, disass->count, statusbar, id); */ do { GBinFormat *format; /* Format du fichier binaire */ GArchInstruction *iter; /* Boucle de parcours */ format = G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)); for (iter = *disass->instrs; iter != NULL; iter = g_arch_instruction_get_next_iter(*disass->instrs, iter, 0)) { g_arch_instruction_call_hook(iter, IPH_LINK, proc, /*ctx*/NULL, format); } } while (0); // plugins ////////////////////////// process_disassembly_event(PGA_DISASSEMBLY_HOOKED_LINK, disass->binary); //gtk_extended_status_bar_remove(statusbar, id); //run_plugins_on_binary(disass->binary, PGA_BINARY_DISASSEMBLED, true); do { GBinFormat *format; /* Format du fichier binaire */ GArchInstruction *iter; /* Boucle de parcours */ format = G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)); for (iter = *disass->instrs; iter != NULL; iter = g_arch_instruction_get_next_iter(*disass->instrs, iter, 0)) { g_arch_instruction_call_hook(iter, IPH_POST, proc, /*ctx*/NULL, format); } } while (0); // plugins ////////////////////////// process_disassembly_event(PGA_DISASSEMBLY_HOOKED_POST, disass->binary); /** * TODO : établir les couvertures de fonctions, * pour être en mesure de disposer de résolution de type XXX+yyy lors * de l'établissement des liens. */ /* Seconde étape */ routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count); id = gtk_extended_status_bar_push(statusbar, _("Finding remaining limits..."), true); //qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare); limit_all_routines(disass->format, proc, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); //run_plugins_on_binary(disass->binary, PGA_BINARY_BOUNDED, true); // plugins ////////////////////////// process_disassembly_event(PGA_DISASSEMBLY_LIMITED, disass->binary); /* Troisième étape */ id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true); /** * * Lequel choisir ??? G_BIN_FORMAT(disass->format) G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary) */ establish_links_between_instructions(*disass->instrs, G_BIN_FORMAT(disass->format), statusbar, id); gtk_extended_status_bar_remove(statusbar, id); //run_plugins_on_binary(disass->binary, PGA_BINARY_LINKED, true); // plugins ////////////////////////// process_disassembly_event(PGA_DISASSEMBLY_LINKED, disass->binary); /* Quatrième étape */ id = gtk_extended_status_bar_push(statusbar, _("Detecting loops..."), true); detect_loops_in_code(proc, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); /// // plugins ////////////////////////// process_disassembly_event(PGA_DISASSEMBLY_LOOPS, disass->binary); /* Cinquième étape */ id = gtk_extended_status_bar_push(statusbar, _("Grouping routines instructions..."), true); //qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare); group_routines_instructions(proc, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); //run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true); process_disassembly_event(PGA_DISASSEMBLY_GROUPED, disass->binary); /* Sixième étape */ id = gtk_extended_status_bar_push(statusbar, _("Ranking each instructions block..."), true); //qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare); rank_routines_blocks(routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); //run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true); process_disassembly_event(PGA_DISASSEMBLY_RANKED, disass->binary); /* Septième étape */ //id = gtk_extended_status_bar_push(statusbar, _("Printing disassembled code..."), true); qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_compare); proc = g_loaded_binary_get_processor(disass->binary); print_disassembled_instructions(disass->buffer, disass->format, proc, *disass->instrs, routines, routines_count, statusbar, id); g_object_unref(G_OBJECT(proc)); process_disassembly_event(PGA_DISASSEMBLY_ENDED, disass->binary); printf("---fin\n"); //gtk_extended_status_bar_remove(statusbar, id); //run_plugins_on_binary(disass->binary, PGA_BINARY_PRINTED, true); } #if 0 /****************************************************************************** * * * Paramètres : disass = analyse à mener. * * statusbar = barre de statut à tenir informée. * * * * Description : Assure le désassemblage en différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_disassembly_process_old(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar) { #ifdef DEBUG unsigned int valid; /* Instructions traduites */ unsigned int db; /* Instructions non décodées */ unsigned int valid_sum; /* Instructions traduites */ unsigned int instr_sum; /* Instructions totales */ size_t i; /* Boucle de parcours */ #endif GBinRoutine **routines; /* Liste des routines trouvées */ size_t routines_count; /* Nombre de ces routines */ bstatus_id_t id; /* Identifiant de statut */ routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count); /* Première étape */ id = gtk_extended_status_bar_push(statusbar, _("Disassembling..."), true); *disass->instrs = disassemble_binary_parts(disass->binary, disass->parts, disass->count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); #ifdef DEBUG valid_sum = 0; instr_sum = 0; for (i = 0; i < disass->count; i++) { g_binary_part_get_checkup(disass->parts[i], &valid, &db); valid_sum += valid; instr_sum += (valid + db); } log_variadic_message(LMT_WARNING, _("Disassembled instructions : %u %% (%u / %d)"), (valid_sum * 100) / instr_sum, valid_sum, instr_sum); #endif run_plugins_on_binary(disass->binary, PGA_BINARY_DISASSEMBLED, true); /* Seconde étape */ id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true); establish_links_between_lines(*disass->instrs, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); run_plugins_on_binary(disass->binary, PGA_BINARY_LINKED, true); /* Troisième étape */ id = gtk_extended_status_bar_push(statusbar, _("Finding remaining limits..."), true); qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare); limit_all_routines(*disass->instrs, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); run_plugins_on_binary(disass->binary, PGA_BINARY_BOUNDED, true); /* Quatrième étape */ id = gtk_extended_status_bar_push(statusbar, _("Detecting loops..."), true); detect_loops_in_code(*disass->instrs, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); /* Cinquième étape */ id = gtk_extended_status_bar_push(statusbar, _("Grouping routines instructions..."), true); qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare); group_routines_instructions(*disass->instrs, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true); /* Sixième étape */ id = gtk_extended_status_bar_push(statusbar, _("Ranking each instructions block..."), true); qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare); rank_routines_blocks(routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true); /* Septième étape */ id = gtk_extended_status_bar_push(statusbar, _("Printing disassembled code..."), true); qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_compare); print_disassembled_instructions(disass->buffer, disass->format, *disass->instrs, routines, routines_count, statusbar, id); gtk_extended_status_bar_remove(statusbar, id); run_plugins_on_binary(disass->binary, PGA_BINARY_PRINTED, true); } #endif /* ---------------------------------------------------------------------------------- */ /* GESTION GLOBALE DE PROCEDURE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : buffer = tampon de destination pour le texte. * * filename = nom du fichier ciblé à décompiler. * * data = données en mémoire pour l'empreinte. * * length = quantité de données à prendre en compte. * * * * Description : Construit la description d'introduction du désassemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void build_disass_prologue(GCodeBuffer *buffer, const char *filename, const char *checksum) { GLangOutput *output; /* Modèle de sortie adéquat */ GBufferLine *line; /* Ligne de destination */ size_t len; /* Taille du texte */ char *content; /* Contenu textuel d'une ligne */ output = g_asm_output_new(); line = g_lang_output_start_comments(output, buffer); if (line != NULL) g_buffer_line_start_merge_at(line, BLC_PHYSICAL); /* Introduction */ line = g_lang_output_continue_comments(output, buffer, SL(_("Disassembly generated by Chrysalide"))); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); line = g_lang_output_continue_comments(output, buffer, SL(_("Chrysalide is free software - © 2008-2015 Cyrille Bagard"))); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); line = g_lang_output_continue_comments(output, buffer, NULL, 0); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); /* Fichier */ len = strlen(_("File: ")) + strlen(filename) + 1; content = (char *)calloc(len, sizeof(char)); snprintf(content, len, "%s%s", _("File: "), filename); line = g_lang_output_continue_comments(output, buffer, content, len - 1); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); free(content); /* Checksum SHA256 */ len = strlen(_("Sha256: ")) + strlen(checksum); content = (char *)calloc(len + 1, sizeof(char)); snprintf(content, len + 1, "%s%s", _("Sha256: "), checksum); line = g_lang_output_continue_comments(output, buffer, content, len - 1); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); free(content); /* Ligne de séparation */ line = g_lang_output_continue_comments(output, buffer, NULL, 0); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); /* Conclusion */ line = g_lang_output_end_comments(output, buffer); if (line != NULL) g_buffer_line_start_merge_at(line, BLC_PHYSICAL); g_object_unref(G_OBJECT(output)); } /****************************************************************************** * * * Paramètres : binary = représentation de binaire chargé. * * parts = parties binaires à désassembler. * * count = nombre de parties à traiter. * * instrs = liste des instructions chargées. [OUT] * * buffer = tampon de code mis en place. [OUT] * * ack = fonction à appeler une fois l'opération terminée. * * * * Description : Procède au désassemblage d'un contenu binaire donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void disassemble_binary(GLoadedBinary *binary, GArchInstruction **instrs, GCodeBuffer **buffer, disassembly_ack_fc ack) { GBinFormat *format; /* Format associé au binaire */ GBinContent *content; /* Contenu bianire manipulé */ const gchar *checksum; /* Identifiant de binaire */ GDelayedDisassembly *disass; /* Désassemblage à mener */ GWorkQueue *queue; /* Gestionnaire de différés */ *buffer = g_code_buffer_new(BLC_ASSEMBLY); format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); content = g_binary_format_get_content(format); checksum = g_binary_content_get_cheksum(content); g_object_unref(G_OBJECT(content)); build_disass_prologue(*buffer, g_binary_content_describe(content, true), checksum); disass = g_delayed_disassembly_new(binary, instrs, *buffer); g_signal_connect(disass, "work-completed", G_CALLBACK(ack), binary); queue = get_work_queue(); g_work_queue_schedule_work(queue, G_DELAYED_WORK(disass), DEFAULT_WORK_GROUP); }