/* Chrysalide - Outil d'analyse de fichiers binaires * goto.c - boîte de dialogue pour les sauts à une adresse donnée * * Copyright (C) 2015-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 "select.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "finder.h" /* ------------------------ PARTIE PRINCIPALE DE L'ASSISTANT ------------------------ */ /* Colonnes de la liste des binaires */ typedef enum _CurrentProjectBinaries { CPB_BINARY, /* Instance GLib du bianire */ CPB_FILENAME, /* Chemin d'accès au fichier */ CPB_COUNT /* Nombre de colonnes */ } CurrentProjectBinaries; /* Ferme l'assistant sans dérouler la procédure. */ static void rop_finder_assistant_cancel(GtkAssistant *, gpointer); /* Ferme l'assistant et déroule la procédure. */ static void rop_finder_assistant_apply(GtkAssistant *, GObject *); /* Accompagne le chargement de certaines pages de l'assistant. */ static void rop_finder_assistant_prepare(GtkAssistant *, GtkWidget *, GObject *); /* ------------------------ DEFINITION DES ENTREES / SORTIES ------------------------ */ /* Ajoute le panneau de choix quant aux fichiers d'E/S. */ static void register_input_output_panel(GtkAssistant *, GObject *); /* Construit la sélection d'un binaire déjà chargé. */ static GtkWidget *load_and_populate_current_project_binaries(GObject *); /* Réagit à un changement de sélection du binaire d'entrée. */ static void on_loaded_binary_selection_change(GtkComboBox *, GObject *); /* Met à jour l'accès à la définition d'un fichier de sortie. */ static void on_output_need_toggle(GtkToggleButton *, GObject *); /* Sélectionne ou non un nouveau fichier de sortie. */ static void on_output_filename_browsing_clicked(GtkButton *, GObject *); /* ------------------------- SUIVI DE LA PHASE DE RECHERCHE ------------------------- */ /* Ajoute le panneau de suivi des opérations de recherche. */ static void register_search_display_panel(GtkAssistant *, GObject *); /* Initialise une ligne de rapport quant aux opérations menées. */ static void init_rop_search_step(GtkGrid *, gint, GObject *, const char *, const char *, GtkWidget *); /* Réinitialise tous les rapports de recherches imprimés. */ static void reset_rop_search_steps(GObject *); /* Description d'une évolution du processus */ typedef struct _search_step { GObject *ref; /* Espace de référencements */ union { struct { const char *key; /* Clef d'accès partielle */ bool dynamic; /* Mémoire à libérer ? */ union { const char *msg; /* Message de conclusion */ char *dmsg; /* Message de conclusion */ }; bool success; /* Indication claire */ }; gdouble fraction; /* Avancée du désasssemblage */ struct { GExeFormat *format; /* Format binaire chargé */ found_rop_list *list; /* Liste de gadgets ROP trouvés*/ size_t count; /* Nombre de gadgets trouvés */ }; }; } search_step; /* Affiche un message de statut quant aux recherches en cours. */ static gboolean print_status_of_rop_search_step(search_step *); /* Affiche un message de statut quant aux recherches en cours. */ static void push_status_printing_of_rop_search_step(GObject *, const char *, const char *, bool); /* Affiche un message de statut quant aux recherches en cours. */ static void push_dyn_status_printing_of_rop_search_step(GObject *, const char *, char *, bool); /* Actualise la barre de progression affichée. */ static gboolean update_progress_bar_fraction(search_step *); /* Lance l'actualisation de la barre de progression affichée. */ static void push_new_progress_fraction(GObject *, gdouble); /* Enregistre une référence vers les gadgets trouvés. */ static gboolean register_found_rop_gadgets(search_step *); /* Lance une conservation des gadgets trouvés. */ static void push_found_rop_gadgets(GObject *, GExeFormat *, found_rop_list *, size_t); /* Charge un format binaire interne déjà chargé. */ static GExeFormat *load_internal_format_for_rop_gadgets(GObject *); /* Procède à la recherche de gadgets de façon séparée. */ static gpointer look_for_rop_gadgets(GObject *); /* ----------------------- MISE EN FORME DES GADGETS PRESENTS ----------------------- */ /* Colonnes de la liste des symboles */ typedef enum _FoundROPGadget { FRG_CATEGORY, /* Catégorie d'appartenance */ FRG_RAW_VIRTUAL, /* Correspondance virtuelle */ FRG_RAW, /* Brut pour recherche */ FRG_VIRTUAL, /* Correspondance virtuelle */ FRG_CONTENT, /* Contenu des lignes visées */ FRG_COUNT /* Nombre de colonnes */ } FoundROPGadget; /* Ajoute le panneau de sélection des gadgets ROP identifiés. */ static void register_rop_list_panel(GtkAssistant *, GObject *); /* Lance l'actualisation du filtrage des gadgets ROP. */ static void on_rop_gadgets_category_changed(GtkComboBox *, GObject *); /* Lance l'actualisation du filtrage des gadgets ROP. */ static void on_rop_gadgets_filter_changed(GtkSearchEntry *, GObject *); /* Détermine la visibilité de tel ou tel gadget ROP. */ static gboolean filter_visible_rop_gadgets(GtkTreeModel *, GtkTreeIter *, GObject *); /* Ajoute de nouvelles chaînes de gadgets localisées. */ static void add_new_gadgets_for_category(GExeFormat *, GtkComboBoxText *, GtkTreeStore *, const char *, rop_chain **, size_t); /* ---------------------------------------------------------------------------------- */ /* PARTIE PRINCIPALE DE L'ASSISTANT */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : parent = fenêtre principale de l'éditeur. * * * * Description : Crée et affiche un assistant de sélection de gadgets ROP. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void run_rop_finder_assistant(GtkWindow *parent) { GtkWidget *assistant; /* Fenêtre à afficher */ GObject *ref; /* Espace de référencement */ assistant = gtk_assistant_new(); gtk_widget_set_size_request(assistant, 900, 550); gtk_window_set_position(GTK_WINDOW(assistant), GTK_WIN_POS_CENTER); gtk_window_set_title(GTK_WINDOW(assistant), _("Export assistant")); gtk_window_set_modal(GTK_WINDOW(assistant), TRUE); gtk_window_set_transient_for(GTK_WINDOW(assistant), parent); ref = G_OBJECT(assistant); register_input_output_panel(GTK_ASSISTANT(assistant), ref); register_search_display_panel(GTK_ASSISTANT(assistant), ref); register_rop_list_panel(GTK_ASSISTANT(assistant), ref); g_signal_connect(G_OBJECT(assistant), "cancel", G_CALLBACK(rop_finder_assistant_cancel), NULL); g_signal_connect(G_OBJECT(assistant), "close", G_CALLBACK(rop_finder_assistant_cancel), NULL); g_signal_connect(G_OBJECT(assistant), "apply", G_CALLBACK(rop_finder_assistant_apply), ref); g_signal_connect(G_OBJECT(assistant), "prepare", G_CALLBACK(rop_finder_assistant_prepare), ref); gtk_widget_show_all(assistant); } /****************************************************************************** * * * Paramètres : assistant = fenêtre d'assistance à traiter. * * data = adresse non utilisée ici. * * * * Description : Ferme l'assistant sans dérouler la procédure. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void rop_finder_assistant_cancel(GtkAssistant *assistant, gpointer data) { gtk_widget_destroy(GTK_WIDGET(assistant)); } /****************************************************************************** * * * Paramètres : assistant = fenêtre d'assistance à traiter. * * ref = adresse de l'espace de référencement global. * * * * Description : Ferme l'assistant et déroule la procédure. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void rop_finder_assistant_apply(GtkAssistant *assistant, GObject *ref) { GtkEntry *entry; /* Zone de saisie */ const gchar *filename; /* Chemin d'accès du fichier */ int fd; /* Flux ouvert en écriture */ GtkTreeView *treeview; /* Arborescence à actualiser */ GtkTreeModel *model; /* Modèle de gestion */ GtkTreeIter iter; /* Boucle de parcours */ gboolean loop; /* Poursuite de la boucle ? */ gchar *virtual; /* Adresse correspondante */ gchar *raw; /* ROP en format texte simple */ /* Fichier de sortie */ entry = GTK_ENTRY(g_object_get_data(ref, "output_filename")); filename = gtk_entry_get_text(entry); fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); if (fd == -1) { perror("open"); return; } /* Boucle de parcours */ treeview = GTK_TREE_VIEW(g_object_get_data(ref, "treeview")); model = gtk_tree_view_get_model(treeview); for (loop = gtk_tree_model_get_iter_first(model, &iter); loop; loop = gtk_tree_model_iter_next(model, &iter)) { gtk_tree_model_get(model, &iter, FRG_RAW_VIRTUAL, &virtual, FRG_RAW, &raw, -1); dprintf(fd, "%s\t%s\n", virtual, raw); g_free(virtual); g_free(raw); } /* Conclusion */ close(fd); } /****************************************************************************** * * * Paramètres : assistant = fenêtre d'assistance à traiter. * * page = élément de l'assistant à préparer. * * ref = adresse de l'espace de référencement global. * * * * Description : Accompagne le chargement de certaines pages de l'assistant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void rop_finder_assistant_prepare(GtkAssistant *assistant, GtkWidget *page, GObject *ref) { GtkWidget *test; /* Reconnaissance à l'aveugle */ GThread *thread; /* Tâche de fond à programmer */ test = gtk_assistant_get_nth_page(assistant, 1); if (test == page) { reset_rop_search_steps(ref); thread = g_thread_new("gadgets_finder", (GThreadFunc)look_for_rop_gadgets, ref); g_thread_unref(thread); } } /* ---------------------------------------------------------------------------------- */ /* DEFINITION DES ENTREES / SORTIES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : assistant = fenêtre d'assistance à compléter. * * ref = espace de référencements inter-panneaux. * * * * Description : Ajoute le panneau de choix quant aux fichiers d'E/S. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void register_input_output_panel(GtkAssistant *assistant, GObject *ref) { GtkWidget *vbox; /* Support principal */ GtkWidget *frame; /* Support avec encadrement */ GtkWidget *sub_vbox; /* Division verticale */ GtkWidget *combobox; /* Sélection du binaire interne*/ GtkWidget *sub_hbox; /* Division horizontale */ GtkWidget *entry; /* Zone de saisie de texte */ GtkWidget *button; /* Sélection de fichier */ GtkWidget *checkbutton; /* Coche pour une option */ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); gtk_widget_show(vbox); /* Fichier de sortie */ sub_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show(sub_vbox); frame = qck_create_frame(_("Input binary"), sub_vbox, 0, 0, 12, 8); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0); combobox = load_and_populate_current_project_binaries(ref); gtk_box_pack_start(GTK_BOX(sub_vbox), combobox, TRUE, TRUE, 0); /* Fichier de sortie */ sub_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show(sub_vbox); frame = qck_create_frame(_("Ouput results"), sub_vbox, 0, 0, 12, 8); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0); checkbutton = qck_create_check_button(ref, "use_output", _("Save selected ROP gadgets in a file:"), G_CALLBACK(on_output_need_toggle), ref); gtk_widget_show(checkbutton); gtk_box_pack_start(GTK_BOX(sub_vbox), checkbutton, FALSE, FALSE, 0); sub_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_show(sub_hbox); gtk_box_pack_start(GTK_BOX(sub_vbox), sub_hbox, FALSE, TRUE, 0); entry = qck_create_entry(ref, "output_filename", NULL); gtk_box_pack_start(GTK_BOX(sub_hbox), entry, TRUE, TRUE, 0); button = qck_create_button(ref, "output_browser", _("Browse..."), G_CALLBACK(on_output_filename_browsing_clicked), assistant); gtk_box_pack_start(GTK_BOX(sub_hbox), button, FALSE, FALSE, 0); /* Actualisation des accès */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), FALSE); on_output_need_toggle(GTK_TOGGLE_BUTTON(checkbutton), ref); /* Intégration */ gtk_assistant_append_page(assistant, vbox); gtk_assistant_set_page_title(assistant, vbox, _("Input / output")); gtk_assistant_set_page_type(assistant, vbox, GTK_ASSISTANT_PAGE_INTRO); } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * * * Description : Construit la sélection d'un binaire déjà chargé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *load_and_populate_current_project_binaries(GObject *ref) { GtkWidget *result; /* Composant à retourner */ GStudyProject *project; /* Projet courant */ GLoadedContent *current; /* Contenu actif courant */ gint selected; /* Indice à sélectionner */ GtkListStore *store; /* Modèle de gestion en liste */ GLoadedContent **contents; /* Liste de contenus chargés */ size_t count; /* Taille de cette liste */ size_t i; /* Boucle de parcours */ GLoadedBinary *binary; /* Contenu de code binaire */ GtkTreeIter iter; /* Point d'insertion */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ /* Récupération des éléments courants */ project = get_current_project(); current = get_current_content(); /* Constitution d'une liste de binaires courants */ selected = -1; store = gtk_list_store_new(CPB_COUNT, G_TYPE_OBJECT, G_TYPE_STRING); contents = g_study_project_get_contents(project, &count); if (contents != NULL) { for (i = 0; i < count; i++) { if (G_IS_LOADED_BINARY(contents[i])) { binary = G_LOADED_BINARY(contents[i]); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, CPB_BINARY, binary, CPB_FILENAME, g_loaded_binary_get_name(binary, true), -1); if (binary == (GLoadedBinary *)current) selected = i; } g_object_unref(G_OBJECT(contents[i])); } free(contents); } /* Mise en place d'un affichage graphique */ result = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); g_object_set_data(ref, "input_binary", result); g_signal_connect(result, "changed", G_CALLBACK(on_loaded_binary_selection_change), ref); gtk_widget_show(result); gtk_combo_box_set_active(GTK_COMBO_BOX(result), selected); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(result), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(result), renderer, "text", CPB_FILENAME, NULL); g_object_unref(G_OBJECT(store)); /* Sortie propre */ g_object_unref(G_OBJECT(current)); g_object_unref(G_OBJECT(project)); return result; } /****************************************************************************** * * * Paramètres : combo = composant graphique de sélection concerné. * * ref = espace de référencement principal. * * * * Description : Réagit à un changement de sélection du binaire d'entrée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_loaded_binary_selection_change(GtkComboBox *combo, GObject *ref) { gint selected; /* Indice sélectionné */ GtkWidget *page; /* Page de la partie terminée */ selected = gtk_combo_box_get_active(combo); page = gtk_assistant_get_nth_page(GTK_ASSISTANT(ref), 0); if (page != NULL) gtk_assistant_set_page_complete(GTK_ASSISTANT(ref), page, selected != -1); } /****************************************************************************** * * * Paramètres : button = coche dont le status vient de changer. * * ref = espace de référencements inter-panneaux. * * * * Description : Met à jour l'accès à la définition d'un fichier de sortie. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_output_need_toggle(GtkToggleButton *button, GObject *ref) { gboolean state; /* Etat du bouton courant */ GtkWidget *widget; /* Element dont l'accès change */ state = gtk_toggle_button_get_active(button); widget = GTK_WIDGET(g_object_get_data(ref, "output_filename")); if (widget != NULL) gtk_widget_set_sensitive(widget, state); widget = GTK_WIDGET(g_object_get_data(ref, "output_browser")); if (widget != NULL) gtk_widget_set_sensitive(widget, state); } /****************************************************************************** * * * Paramètres : button = bouton d'édition de la sélection. * * ref = espace de référencement principal. * * * * Description : Sélectionne ou non un nouveau fichier de sortie. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_output_filename_browsing_clicked(GtkButton *button, GObject *ref) { GtkWidget *dialog; /* Boîte à afficher */ gchar *filename; /* Nom du fichier à intégrer */ GtkEntry *entry; /* Zone de saisie à maj. */ dialog = gtk_file_chooser_dialog_new(_("Choose an output filename"), GTK_WINDOW(ref), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_ACCEPT, NULL); entry = GTK_ENTRY(g_object_get_data(ref, "output_filename")); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), gtk_entry_get_text(entry)); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); gtk_entry_set_text(GTK_ENTRY(entry), filename); g_free(filename); } gtk_widget_destroy(dialog); } /* ---------------------------------------------------------------------------------- */ /* SUIVI DE LA PHASE DE RECHERCHE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : assistant = fenêtre d'assistance à compléter. * * ref = espace de référencements inter-panneaux. * * * * Description : Ajoute le panneau de suivi des opérations de recherche. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void register_search_display_panel(GtkAssistant *assistant, GObject *ref) { GtkGrid *grid; /* Table de résumé */ GtkWidget *pbar; /* barre de progression */ grid = GTK_GRID(gtk_grid_new()); gtk_grid_set_column_spacing(grid, 8); gtk_grid_set_row_spacing(grid, 8); g_object_set(G_OBJECT(grid), "halign", GTK_ALIGN_CENTER, "valign", GTK_ALIGN_CENTER, "margin-bottom", 100, NULL); /* Représentation des étapes */ init_rop_search_step(grid, 0, ref, "loading", _("Loading the input binary..."), NULL); init_rop_search_step(grid, 1, ref, "format", _("Detecting the proper format..."), NULL); pbar = gtk_progress_bar_new(); g_object_set(G_OBJECT(pbar), "valign", GTK_ALIGN_CENTER, NULL); gtk_widget_show(pbar); init_rop_search_step(grid, 2, ref, "gadgets", _("Looking for all ROP gadgets..."), pbar); init_rop_search_step(grid, 3, ref, "final", _("Results:"), NULL); /* Intégration */ gtk_assistant_append_page(assistant, GTK_WIDGET(grid)); gtk_assistant_set_page_title(assistant, GTK_WIDGET(grid), _("Search process")); gtk_assistant_set_page_type(assistant, GTK_WIDGET(grid), GTK_ASSISTANT_PAGE_PROGRESS); } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * key = clef partielle d'accès aux composants concernés. * * info = message d'information annonçant la conclusion. * * pbar = éventuel composant de statut ou NULL. * * * * Description : Initialise une ligne de rapport quant aux opérations menées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void init_rop_search_step(GtkGrid *grid, gint top, GObject *ref, const char *key, const char *info, GtkWidget *pbar) { char *access; /* Chemin d'accès final */ GtkWidget *render; /* Image de statut à afficher */ GtkWidget *label; /* Etiquette d'indication */ /* Icone de représentation */ access = strdup("process_"); access = stradd(access, key); access = stradd(access, "_icon"); render = gtk_image_new_from_icon_name("dialog-question", GTK_ICON_SIZE_DND); g_object_set_data(ref, access, render); gtk_widget_show(render); gtk_grid_attach(grid, render, 0, top, 1, 1); free(access); /* Désignation humaine d'indicatif */ access = strdup("process_"); access = stradd(access, key); access = stradd(access, "_caption"); label = qck_create_label(ref, access, info); gtk_grid_attach(grid, label, 1, top, 1, 1); free(access); /* Statut final */ access = strdup("process_"); access = stradd(access, key); access = stradd(access, "_status"); if (pbar == NULL) { label = qck_create_label(ref, access, "done"); gtk_grid_attach(grid, label, 2, top, 1, 1); } else { g_object_set_data(ref, access, pbar); gtk_grid_attach(grid, pbar, 2, top, 1, 1); } free(access); } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * * * Description : Réinitialise tous les rapports de recherches imprimés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void reset_rop_search_steps(GObject *ref) { size_t i; /* Boucle de parcours */ char *access; /* Chemin d'accès final */ GObject *render; /* Image de statut à afficher */ GtkLabel *label; /* Etiquette d'indication */ GtkProgressBar *pbar; /* Barre à mettre à jour */ static const char *icon_keys[] = { "loading", "format", "gadgets", "final" }; static const char *status_keys[] = { "loading", "format", "final" }; /* Réinitialisation des images */ for (i = 0; i < ARRAY_SIZE(icon_keys); i++) { access = strdup("process_"); access = stradd(access, icon_keys[i]); access = stradd(access, "_icon"); render = G_OBJECT(g_object_get_data(ref, access)); g_object_set(render, "icon-name", "dialog-question", NULL); free(access); } /* Statut final */ for (i = 0; i < ARRAY_SIZE(status_keys); i++) { access = strdup("process_"); access = stradd(access, status_keys[i]); access = stradd(access, "_status"); label = GTK_LABEL(g_object_get_data(ref, access)); gtk_label_set_text(label, ""); free(access); } /* Progression des recherches */ pbar = GTK_PROGRESS_BAR(g_object_get_data(ref, "process_gadgets_status")); gtk_progress_bar_set_fraction(pbar, 0.0); } /****************************************************************************** * * * Paramètres : step = informations quant à l'étape avancée. * * * * Description : Affiche un message de statut quant aux recherches en cours. * * * * Retour : FALSE pour ne pas reprogrammer l'exécution de la tâche. * * * * Remarques : - * * * ******************************************************************************/ static gboolean print_status_of_rop_search_step(search_step *step) { char *access; /* Chemin d'accès final */ GObject *render; /* Image de statut à afficher */ GtkLabel *status; /* Bilan à faire paraître */ /* Icone de représentation */ access = strdup("process_"); access = stradd(access, step->key); access = stradd(access, "_icon"); render = G_OBJECT(g_object_get_data(step->ref, access)); g_object_set(render, "icon-name", step->success ? "face-smile" : "face-sad", NULL); free(access); /* Mot de la fin */ if (step->msg != NULL) { access = strdup("process_"); access = stradd(access, step->key); access = stradd(access, "_status"); status = GTK_LABEL(g_object_get_data(step->ref, access)); gtk_label_set_text(status, step->msg); free(access); } /* Nettoyage final */ if (step->dynamic) free(step->dmsg); free(step); return FALSE; } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * key = clef partielle d'accès aux composants concernés. * * msg = message d'information accompagnant la conclusion. * * success = indication quant à la réussite de l'opération. * * * * Description : Affiche un message de statut quant aux recherches en cours. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void push_dyn_status_printing_of_rop_search_step(GObject *ref, const char *key, char *dmsg, bool success) { search_step *step; /* Informations d'étape */ step = (search_step *)calloc(1, sizeof(search_step)); step->ref = ref; step->key = key; step->dynamic = true; step->dmsg = dmsg; step->success = success; g_idle_add((GSourceFunc)print_status_of_rop_search_step, step); } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * key = clef partielle d'accès aux composants concernés. * * msg = message d'information accompagnant la conclusion. * * success = indication quant à la réussite de l'opération. * * * * Description : Affiche un message de statut quant aux recherches en cours. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void push_status_printing_of_rop_search_step(GObject *ref, const char *key, const char *msg, bool success) { search_step *step; /* Informations d'étape */ step = (search_step *)calloc(1, sizeof(search_step)); step->ref = ref; step->key = key; step->dynamic = false; step->msg = msg; step->success = success; g_idle_add((GSourceFunc)print_status_of_rop_search_step, step); } /****************************************************************************** * * * Paramètres : step = informations quant à l'étape avancée. * * * * Description : Actualise la barre de progression affichée. * * * * Retour : FALSE pour ne pas reprogrammer l'exécution de la tâche. * * * * Remarques : - * * * ******************************************************************************/ static gboolean update_progress_bar_fraction(search_step *step) { GtkProgressBar *pbar; /* Barre à mettre à jour */ pbar = GTK_PROGRESS_BAR(g_object_get_data(step->ref, "process_gadgets_status")); gtk_progress_bar_set_fraction(pbar, step->fraction); /* Nettoyage final */ free(step); return FALSE; } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * fraction = avancée globale du désassemblage en cours. * * * * Description : Lance l'actualisation de la barre de progression affichée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void push_new_progress_fraction(GObject *ref, gdouble fraction) { search_step *step; /* Informations d'étape */ step = (search_step *)calloc(1, sizeof(search_step)); step->ref = ref; step->fraction = fraction; g_idle_add((GSourceFunc)update_progress_bar_fraction, step); } /****************************************************************************** * * * Paramètres : step = informations quant à l'étape avancée. * * * * Description : Enregistre une référence vers les gadgets trouvés. * * * * Retour : FALSE pour ne pas reprogrammer l'exécution de la tâche. * * * * Remarques : - * * * ******************************************************************************/ static gboolean register_found_rop_gadgets(search_step *step) { GtkComboBoxText *combo; /* Sélection d'une catégorie */ GtkTreeView *treeview; /* Arborescence à actualiser */ GtkTreeModelFilter *filter; /* Modèle de gestion associé */ size_t i; /* Boucle de parcours */ GtkWidget *page; /* Page de la partie terminée */ /* Affichage des résulats */ if (step->format != NULL) { combo = GTK_COMBO_BOX_TEXT(g_object_get_data(step->ref, "filter_cat")); treeview = GTK_TREE_VIEW(g_object_get_data(step->ref, "treeview")); filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(treeview)); for (i = 0; i < step->count; i++) add_new_gadgets_for_category(step->format, combo, GTK_TREE_STORE(gtk_tree_model_filter_get_model(filter)), step->list[i].category, step->list[i].gadgets, step->list[i].count); if (step->list != NULL) free_rop_list(step->list); } /* Déverrouillage des accès à la suite */ page = gtk_assistant_get_nth_page(GTK_ASSISTANT(step->ref), 1); gtk_assistant_set_page_complete(GTK_ASSISTANT(step->ref), page, TRUE); /* Nettoyage final */ free(step); return FALSE; } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * format = format binaire chargé. * * list = liste de liste de gadgets pour ROP. * * count = taille de cette liste. * * * * Description : Lance une conservation des gadgets trouvés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void push_found_rop_gadgets(GObject *ref, GExeFormat *format, found_rop_list *list, size_t count) { search_step *step; /* Informations d'étape */ step = (search_step *)calloc(1, sizeof(search_step)); step->ref = ref; step->format = format; step->list = list; step->count = count; g_idle_add((GSourceFunc)register_found_rop_gadgets, step); } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * * * Description : Charge un format binaire interne déjà chargé. * * * * Retour : Nouveau format au contenu à fouiller ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GExeFormat *load_internal_format_for_rop_gadgets(GObject *ref) { GExeFormat *result; /* Format chargé à retourner */ GtkComboBox *combo; /* Composant de sélection */ GtkTreeIter iter; /* Tête de lecture à placer */ GtkTreeModel *model; /* Modèle de gestion */ GLoadedBinary *binary; /* Binaire chargé à utiliser */ combo = GTK_COMBO_BOX(g_object_get_data(ref, "input_binary")); if (!gtk_combo_box_get_active_iter(combo, &iter)) { push_status_printing_of_rop_search_step(ref, "loading", _("unable to get the current binary"), false); return NULL; } model = gtk_combo_box_get_model(combo); gtk_tree_model_get(model, &iter, CPB_BINARY, &binary, -1); push_status_printing_of_rop_search_step(ref, "loading", _("done"), true); result = g_loaded_binary_get_format(binary); push_status_printing_of_rop_search_step(ref, "format", _("already loaded"), true); g_object_unref(G_OBJECT(binary)); return result; } /****************************************************************************** * * * Paramètres : ref = espace de référencements inter-panneaux. * * * * Description : Procède à la recherche de gadgets de façon séparée. * * * * Retour : ? * * * * Remarques : - * * * ******************************************************************************/ static gpointer look_for_rop_gadgets(GObject *ref) { GExeFormat *format; /* Format du binaire à traiter */ found_rop_list *list; /* Liste de gadgets ROP trouvés*/ size_t count; /* Nombre de ces listes */ size_t found; /* Nombre de gadgets trouvés */ size_t i; /* Boucle de parcours */ char *msg; /* Message final à faire passer*/ format = load_internal_format_for_rop_gadgets(ref); if (format == NULL) goto lfrg_unlock; list = list_all_gadgets(format, 7, push_new_progress_fraction, ref, &count); push_status_printing_of_rop_search_step(ref, "gadgets", NULL, true); found = 0; for (i = 0; i < count; i++) found += list[i].count; switch (found) { case 0: msg = strdup(_("No ROP gadget has been found.")); break; case 1: msg = strdup(_("1 ROP gadget has been found.")); break; default: asprintf(&msg, _("%zu gadgets have been found."), found); break; } push_dyn_status_printing_of_rop_search_step(ref, "final", msg, count > 0); push_found_rop_gadgets(ref, format, list, count); lfrg_unlock: return NULL; } /* ---------------------------------------------------------------------------------- */ /* MISE EN FORME DES GADGETS PRESENTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : assistant = fenêtre d'assistance à compléter. * * ref = espace de référencements inter-panneaux. * * * * Description : Ajoute le panneau de sélection des gadgets ROP identifiés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void register_rop_list_panel(GtkAssistant *assistant, GObject *ref) { GtkWidget *vbox; /* Support principal */ GtkWidget *hbox; /* Petite barre supérieure */ GtkWidget *label; /* Etiquette d'indication */ GtkWidget *comboboxentry; /* Liste de sélection simple */ GtkWidget *vseparator; /* Barre de séparation */ GtkWidget *filter; /* Zone de recherche */ GtkWidget *scrollwnd; /* Support défilant */ GtkTreeStore *store; /* Modèle de gestion */ GtkTreeModel *model; /* Modèle de gestion supérieur */ GtkWidget *treeview; /* Affichage de la liste */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); gtk_widget_show(vbox); gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); /* Choix de la catégorie */ label = gtk_label_new(_("ROP selection:")); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); comboboxentry = qck_create_combobox(ref, "filter_cat", G_CALLBACK(on_rop_gadgets_category_changed), ref); gtk_box_pack_start(GTK_BOX(hbox), comboboxentry, FALSE, TRUE, 0); /* Séparation fine */ vseparator = gtk_separator_new(GTK_ORIENTATION_VERTICAL); gtk_widget_show(vseparator); gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0); /* Espace de recherche */ label = gtk_label_new(_("Filter:")); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); filter = gtk_search_entry_new(); g_object_set_data(ref, "filter_rop", filter); gtk_widget_set_tooltip_text(filter, _("Filter gadgets using POSIX extended regular expressions")); g_signal_connect(filter, "search-changed", G_CALLBACK(on_rop_gadgets_filter_changed), ref); gtk_widget_show(filter); gtk_widget_set_hexpand(filter, TRUE); gtk_box_pack_start(GTK_BOX(hbox), filter, TRUE, TRUE, 0); /* Liste arborescente ou linéaire */ scrollwnd = gtk_scrolled_window_new(NULL, NULL); gtk_widget_show(scrollwnd); gtk_box_pack_start(GTK_BOX(vbox), scrollwnd, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwnd), GTK_SHADOW_IN); store = gtk_tree_store_new(FRG_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); model = gtk_tree_model_filter_new(GTK_TREE_MODEL(store), NULL); gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), (GtkTreeModelFilterVisibleFunc)filter_visible_rop_gadgets, ref, NULL); treeview = gtk_tree_view_new_with_model(model); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(treeview), TRUE); g_object_set_data(ref, "treeview", treeview); gtk_widget_show(treeview); gtk_container_add(GTK_CONTAINER(scrollwnd), treeview); /* Cellules d'affichage */ renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Address"), renderer, "markup", FRG_VIRTUAL, NULL); gtk_tree_view_column_set_sort_column_id(column, FRG_VIRTUAL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Gadgets"), renderer, "markup", FRG_CONTENT, NULL); gtk_tree_view_column_set_sort_column_id(column, FRG_CONTENT); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); /* Intégration */ gtk_assistant_append_page(assistant, vbox); gtk_assistant_set_page_title(assistant, vbox, _("ROP Gadgets")); gtk_assistant_set_page_type(assistant, vbox, GTK_ASSISTANT_PAGE_CONFIRM); gtk_assistant_set_page_complete(assistant, vbox, TRUE); } /****************************************************************************** * * * Paramètres : combo = composant de choix contenant le filtre brut. * * ref = espace de référencements inter-panneaux. * * * * Description : Lance l'actualisation du filtrage des gadgets ROP. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_rop_gadgets_category_changed(GtkComboBox *combo, GObject *ref) { GtkTreeView *treeview; /* Arborescence à actualiser */ GtkTreeModelFilter *filter; /* Modèle de gestion associé */ treeview = GTK_TREE_VIEW(g_object_get_data(ref, "treeview")); filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(treeview)); gtk_tree_model_filter_refilter(filter); } /****************************************************************************** * * * Paramètres : entry = entrée de texte contenant le filtre brut. * * ref = espace de référencements inter-panneaux. * * * * Description : Lance l'actualisation du filtrage des gadgets ROP. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_rop_gadgets_filter_changed(GtkSearchEntry *entry, GObject *ref) { regex_t preg; /* Expression régulière de test*/ const gchar *text; /* Texte de l'utilisateur */ GtkStyleContext *context; /* Contexte du thème actuel */ int ret; /* Bilan de mise en place */ GtkTreeView *treeview; /* Arborescence à actualiser */ GtkTreeModelFilter *filter; /* Modèle de gestion associé */ text = gtk_entry_get_text(GTK_ENTRY(entry)); context = gtk_widget_get_style_context(GTK_WIDGET(entry)); if (text[0] != '\0') { ret = regcomp(&preg, text, REG_EXTENDED); if (ret != 0) { gtk_style_context_add_class(context, "filter-error"); return; } regfree(&preg); } gtk_style_context_remove_class(context, "filter-error"); treeview = GTK_TREE_VIEW(g_object_get_data(ref, "treeview")); filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(treeview)); gtk_tree_model_filter_refilter(filter); } /****************************************************************************** * * * Paramètres : model = gestionnaire des lignes et colonnes affichées. * * iter = ligne concernée par l'analyse à mener. * * ref = espace de référencements inter-panneaux. * * * * Description : Détermine la visibilité de tel ou tel gadget ROP. * * * * Retour : Indication d'affichage pour une ligne donnée. * * * * Remarques : - * * * ******************************************************************************/ static gboolean filter_visible_rop_gadgets(GtkTreeModel *model, GtkTreeIter *iter, GObject *ref) { gboolean result; /* Visibilité à retourner */ gchar *category; /* Catégorie d'appartenance */ gchar *raw; /* Brut pour recherche */ GtkComboBoxText *combo; /* Sélection à choix multiples */ gchar *selected; /* Texte de l'utilisateur #1 */ GtkEntry *entry; /* Zone de texte à utiliser */ const gchar *text; /* Texte de l'utilisateur #2 */ regex_t preg; /* Expression régulière de test*/ int ret; /* Bilan de mise en place */ regmatch_t match; /* Récupération des trouvailles*/ result = TRUE; gtk_tree_model_get(model, iter, FRG_CATEGORY, &category, FRG_RAW, &raw, -1); if (category == NULL || raw == NULL) return FALSE; /* Filtre sur les catégories */ combo = g_object_get_data(ref, "filter_cat"); selected = gtk_combo_box_text_get_active_text(combo); result &= (g_strcmp0(category, selected) == 0); g_free(selected); /* Filtre sur les gadgets ROP */ entry = g_object_get_data(ref, "filter_rop"); text = gtk_entry_get_text(GTK_ENTRY(entry)); ret = regcomp(&preg, text, REG_EXTENDED); result &= (ret == 0); if (ret == 0) { ret = regexec(&preg, raw, 1, &match, 0); result &= (ret != REG_NOMATCH); regfree(&preg); } /* Nettoyages finaux */ g_free(category); g_free(raw); return result; } /****************************************************************************** * * * Paramètres : format = format binaire chargé sur lequel se reposer. * * combo = composant de sélection des catégories à compléter.* * store = modèle de gestionnaire pour la liste affichée. * * category = représentation du binaire chargé en mémoire. * * gadgets = liste de listes d'instructions de ROP. * * count = taille de cette liste. * * * * Description : Ajoute de nouvelles chaînes de gadgets localisées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void add_new_gadgets_for_category(GExeFormat *format, GtkComboBoxText *combo, GtkTreeStore *store, const char *category, rop_chain **gadgets, size_t count) { const GBinContent *content; /* Contenu binaire global */ size_t i; /* Boucle de parcours #1 */ char *raw_virtual; /* Transcription pour export */ char *virtual; /* Transcription d'adresse */ char *content_raw; /* Contenu assemblé de chaîne */ char *content_markup; /* Contenu assemblé de chaîne */ rop_chain *chain; /* Accès direct à une chaîne */ size_t j; /* Boucle de parcours #2 */ GArchInstruction *instr; /* Elément de liste de gadgets */ GBufferLine *line; /* Ligne présente à l'adresse */ char *partial_raw; /* Contenu de la ligne visée */ char *partial_markup; /* Contenu de la ligne visée */ GtkTreeIter iter; /* Point d'insertion */ content = g_binary_format_get_content(G_BIN_FORMAT(format)); /* Conversion en contenu textuel */ for (i = 0; i < count; i++) { /* Parcours des différentes lignes */ raw_virtual = NULL; virtual = NULL; content_raw = NULL; content_markup = NULL; chain = gadgets[i]; for (j = 0; j < chain->count; j++) { instr = chain->instrs[j]; line = g_buffer_line_new((mrange_t []){ { { 0 }, 0 } }, BLC_ASSEMBLY); g_line_generator_print(G_LINE_GENERATOR(instr), line, -1, 0, content); if (j == 0) { raw_virtual = g_buffer_line_get_text(line, BLC_VIRTUAL, BLC_VIRTUAL + 1, false); virtual = g_buffer_line_get_text(line, BLC_VIRTUAL, BLC_VIRTUAL + 1, true); } partial_raw = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, false); partial_markup = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, true); g_object_unref(G_OBJECT(line)); if (content_raw != NULL) content_raw = stradd(content_raw, " ; "); content_raw = stradd(content_raw, partial_raw); if (content_markup != NULL) content_markup = stradd(content_markup, " ; "); content_markup = stradd(content_markup, partial_markup); free(partial_raw); free(partial_markup); } /* Insertion finale */ gtk_tree_store_append(store, &iter, NULL); gtk_tree_store_set(store, &iter, FRG_CATEGORY, category, FRG_RAW_VIRTUAL, raw_virtual, FRG_RAW, content_raw, FRG_VIRTUAL, virtual, FRG_CONTENT, content_markup, -1); /* Nettoyage de la mémoire */ free(raw_virtual); free(virtual); free(content_raw); free(content_markup); } g_object_unref(G_OBJECT(content)); /* Rajout de la catégorie et filtre au besoin */ gtk_combo_box_text_append_text(combo, category); if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) == -1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); }