/* 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 Foobar. If not, see . */ #include "gotox.h" #include #include #include #include "../../format/format.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/support.h" /* Colonnes de la liste des symboles */ typedef enum _GotoXColumn { GXC_PHYSICAL, /* Correspondance physique */ GXC_VIRTUAL, /* Correspondance virtuelle */ GXC_PICTURE, /* Image de représentation */ GXC_ADDRESS, /* Adresse mémoire du symbole */ GXC_NAME, /* Désignation humaine */ GXC_CONTENT, /* Contenu de la ligne visée */ GXC_COUNT /* Nombre de colonnes */ } GotoXColumn; /* Réagit à une validation d'une ligne affichée. */ static void on_gotox_row_activated(GtkTreeView *, GtkTreePath *, GtkTreeViewColumn *, GtkDialog *); /* Construit la fenêtre de sélection d'adresses. */ static GtkWidget *create_gotox_dialog(GtkWindow *, GtkTreeStore **); /* Ajoute une nouvelle localisation de destination. */ static void add_new_location_to_list(GtkTreeStore *, GLoadedBinary *, const vmpa2t *, GBinSymbol *); /****************************************************************************** * * * Paramètres : treeview = composant graphique manipulé par l'utilisateur. * * path = chemin d'accès à la ligne activée. * * column = colonne impactée par l'action. * * dialog = boîte de dialogue affichant la liste éditée. * * * * Description : Réagit à une validation d'une ligne affichée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_gotox_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GtkDialog *dialog) { gtk_dialog_response(dialog, GTK_RESPONSE_OK); } /****************************************************************************** * * * Paramètres : parent = fenêtre parente à surpasser. * * store = modèle de gestion pour les éléments de liste. [OUT] * * * * Description : Construit la fenêtre de sélection d'adresses. * * * * Retour : Adresse de la fenêtre mise en place. * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *create_gotox_dialog(GtkWindow *parent, GtkTreeStore **store) { GtkWidget *result; /* Fenêtre à renvoyer */ GtkWidget *dlgvbox; /* Zone principale de la boîte */ GtkWidget *vbox; /* Support à construire #1 */ GtkWidget *scrollwnd; /* Support défilant */ GtkWidget *treeview; /* Affichage de la liste */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ result = gtk_dialog_new(); gtk_window_set_default_size(GTK_WINDOW(result), 600, 350); gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(result), TRUE); gtk_window_set_type_hint(GTK_WINDOW(result), GDK_WINDOW_TYPE_HINT_DIALOG); dlgvbox = gtk_dialog_get_content_area(GTK_DIALOG(result)); gtk_widget_show(dlgvbox); vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); gtk_widget_show(vbox); gtk_box_pack_start(GTK_BOX(dlgvbox), vbox, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); /* 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(GXC_COUNT, G_TYPE_UINT64, G_TYPE_UINT64, CAIRO_GOBJECT_TYPE_SURFACE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(*store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(treeview), TRUE); g_signal_connect(treeview, "row-activated", G_CALLBACK(on_gotox_row_activated), result); g_object_set_data(G_OBJECT(result), "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", GXC_ADDRESS, NULL); gtk_tree_view_column_set_sort_column_id(column, GXC_ADDRESS); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Name")); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_set_attributes(column, renderer, "surface", GXC_PICTURE, NULL); g_object_set(G_OBJECT(renderer), "xpad", 4, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_attributes(column, renderer, "text", GXC_NAME, NULL); gtk_tree_view_column_set_sort_column_id(column, GXC_NAME); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Content"), renderer, "markup", GXC_CONTENT, NULL); gtk_tree_view_column_set_sort_column_id(column, GXC_CONTENT); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); /* Zone de validation */ gtk_dialog_add_button(GTK_DIALOG(result), _("_Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(result), _("_Go"), GTK_RESPONSE_OK); return result; } /****************************************************************************** * * * Paramètres : parent = fenêtre parente à surpasser. * * binary = binaire dont les points d'entrée sont à afficher. * * * * Description : Construit la fenêtre de sélection des points d'entrée. * * * * Retour : Adresse de la fenêtre mise en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *create_gotox_dialog_for_entry_points(GtkWindow *parent, GLoadedBinary *binary) { GtkWidget *result; /* Fenêtre à renvoyer */ GtkTreeStore *store; /* Modèle de gestion */ GBinFormat *format; /* Format associé au binaire */ GBinSymbol **symbols; /* Symboles à représenter */ size_t sym_count; /* Qté de symboles présents */ bool has_entry_points; /* Présences d'insertions ? */ size_t i; /* Boucle de parcours */ vmpa2t addr; /* Localisation de symbole */ /* Mise en place de la boîte de dialogue */ result = create_gotox_dialog(parent, &store); gtk_window_set_title(GTK_WINDOW(result), _("Binary's entry points")); /* Affichage de tous les points d'entrées */ format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); symbols = g_binary_format_get_symbols(format, &sym_count); has_entry_points = false; for (i = 0; i < sym_count; i++) { if (g_binary_symbol_get_target_type(symbols[i]) != STP_ENTRY_POINT) continue; copy_vmpa(&addr, get_mrange_addr(g_binary_symbol_get_range(symbols[i]))); add_new_location_to_list(store, binary, &addr, symbols[i]); has_entry_points = true; } g_object_unref(G_OBJECT(format)); g_object_unref(G_OBJECT(store)); gtk_dialog_set_response_sensitive(GTK_DIALOG(result), GTK_RESPONSE_OK, has_entry_points); return result; } /****************************************************************************** * * * Paramètres : parent = fenêtre parente à surpasser. * * binary = binaire dont les points d'entrée sont à afficher. * * instr = instruction de référence sur laquelle s'appuyer. * * back = sens de la récupérations des instructions visées. * * * * Description : Construit la fenêtre de sélection des références croisées. * * * * Retour : Adresse de la fenêtre mise en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *parent, GLoadedBinary *binary, GArchInstruction *instr, bool back) { GtkWidget *result; /* Fenêtre à renvoyer */ GtkTreeStore *store; /* Modèle de gestion */ size_t count; /* Nombre d'éléments présents */ size_t i; /* Boucle de parcours */ instr_link_t *item; /* Instruction diverse liée */ const vmpa2t *addr; /* Adresse à considérer */ /* Mise en place de la boîte de dialogue */ result = create_gotox_dialog(parent, &store); if (back) gtk_window_set_title(GTK_WINDOW(result), _("List of backward cross references")); else gtk_window_set_title(GTK_WINDOW(result), _("List of forward cross references")); /* Affichage de toutes les instructions référencées */ if (back) { g_arch_instruction_lock_src(instr); count = g_arch_instruction_count_sources(instr); for (i = 0; i < count; i++) { item = g_arch_instruction_get_source(instr, i); addr = get_mrange_addr(g_arch_instruction_get_range(item->linked)); add_new_location_to_list(store, binary, addr, NULL); } g_arch_instruction_unlock_src(instr); } else { g_arch_instruction_lock_dest(instr); count = g_arch_instruction_count_destinations(instr); for (i = 0; i < count; i++) { item = g_arch_instruction_get_destination(instr, i); addr = get_mrange_addr(g_arch_instruction_get_range(item->linked)); add_new_location_to_list(store, binary, addr, NULL); } g_arch_instruction_unlock_dest(instr); } g_object_unref(G_OBJECT(store)); gtk_dialog_set_response_sensitive(GTK_DIALOG(result), GTK_RESPONSE_OK, count > 0); return result; } /****************************************************************************** * * * Paramètres : store = modèle de gestionnaire pour la liste affichée. * * binary = représentation du binaire chargé en mémoire. * * addr = localisation à venir ajouter à la liste. * * hint = éventuel symbole à venir retrouver à l'adresse. * * * * Description : Ajoute une nouvelle localisation de destination. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void add_new_location_to_list(GtkTreeStore *store, GLoadedBinary *binary, const vmpa2t *addr, GBinSymbol *hint) { GBufferCache *cache; /* Tampon de désassemblage */ size_t index; /* Indice de ligne à traiter */ GBufferLine *line; /* Ligne présente à l'adresse */ char *virtual; /* Transcription d'adresse */ const char *label; /* Etiquette de symbole trouvé */ GBinFormat *format; /* Format associé au binaire */ GBinSymbol *symbol; /* Symbole associé à l'adresse */ phys_t diff; /* Décalage vis à vis du début */ char *name; /* Désignation humaine */ gchar *filename; /* Chemin d'accès à utiliser */ cairo_surface_t *icon; /* Image pour les symboles */ char *content; /* Contenu de la ligne visée */ GtkTreeIter iter; /* Point d'insertion */ /* Détermination de la ligne concernée */ cache = g_loaded_binary_get_disassembled_cache(binary); index = g_buffer_cache_find_index_by_addr(cache, addr, true); index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); line = g_buffer_cache_find_line_by_index(cache, index); g_object_unref(G_OBJECT(cache)); /* Adresse en mémoire virtuelle */ if (line != NULL) virtual = g_buffer_line_get_text(line, BLC_VIRTUAL, BLC_VIRTUAL + 1, true); else virtual = strdup(_("")); /* Désignation humaine de l'adresse */ if (hint != NULL) { symbol = hint; g_object_ref(G_OBJECT(symbol)); label = g_binary_symbol_get_label(hint); name = make_symbol_offset(label, 0); } else { format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); if (g_binary_format_resolve_symbol(format, addr, true, &symbol, &diff)) { label = g_binary_symbol_get_label(symbol); /** * Un symbole ne possède pas toujours d'étiquette. * C'est le cas par exemple pour les valeurs chargées par * les instructions ARM de type 'ldr'. */ if (label == NULL) name = strdup(_("")); else name = make_symbol_offset(label, diff); } else { symbol = NULL; name = strdup(_("")); } g_object_unref(G_OBJECT(format)); } /* Image de représentation */ if (symbol == NULL) filename = NULL; else switch (g_binary_symbol_get_target_type(symbol)) { case STP_ENTRY_POINT: filename = find_pixmap_file("entrypoint.png"); break; default: filename = NULL; break; } if (filename != NULL) { icon = cairo_image_surface_create_from_png(filename); g_free(filename); } else icon = NULL; /* Contenu d'assemblage */ if (line != NULL) content = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, true); else content = strdup(_("")); /* Insertion finale */ gtk_tree_store_append(store, &iter, NULL); gtk_tree_store_set(store, &iter, GXC_PHYSICAL, PHYS_CAST(get_phy_addr(addr)), GXC_VIRTUAL, VIRT_CAST(get_virt_addr(addr)), GXC_PICTURE, icon, GXC_ADDRESS, virtual, GXC_NAME, name, GXC_CONTENT, content, -1); if (symbol != NULL) g_object_unref(G_OBJECT(symbol)); if (virtual != NULL) free(virtual); if (icon != NULL) cairo_surface_destroy(icon); free(name); if (content != NULL) free(content); if (line != NULL) g_object_unref(G_OBJECT(line)); } /****************************************************************************** * * * Paramètres : dialog = boîte de dialogue ayant reçu une validation. * * * * Description : Fournit l'adresse obtenue par la saisie de l'utilisateur. * * * * Retour : Adresse reccueillie par la boîte de dialogue ou NULL si rien.* * * * Remarques : - * * * ******************************************************************************/ vmpa2t *get_address_from_gotox_dialog(GtkWidget *dialog) { vmpa2t *result; /* Adresse à retourner */ GtkTreeView *treeview; /* Liste d'adresses à lire */ GtkTreeSelection *selection; /* Sélection courante */ GtkTreeModel *model; /* Modèle de gestionnaire */ GList *selected; /* Liste des sélections */ GtkTreeIter iter; /* Tête de lecture */ G_TYPE_PHYS phys; /* Position physique */ G_TYPE_VIRT virt; /* Adresse virtuelle */ treeview = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(dialog), "treeview")); selection = gtk_tree_view_get_selection(treeview); selected = gtk_tree_selection_get_selected_rows(selection, &model); if (selected == NULL) return NULL; if (!gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)selected->data)) return NULL; gtk_tree_model_get(model, &iter, GXC_PHYSICAL, &phys, GXC_VIRTUAL, &virt, -1); result = make_vmpa(phys, virt); g_list_free_full(selected, (GDestroyNotify)gtk_tree_path_free); return result; }