/* Chrysalide - Outil d'analyse de fichiers binaires
* assign.c - renseignement des importations sous forme d'ordinaux
*
* Copyright (C) 2021 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 "assign.h"
#include
#include
#include
#include
#include
#include "ordinals.h"
#define G_TYPE_ORDINAL_RESOLVER g_ordinal_resolver_get_type()
#define G_ORDINAL_RESOLVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ORDINAL_RESOLVER, GOrdinalResolver))
#define G_IS_ORDINAL_RESOLVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ORDINAL_RESOLVER))
#define G_ORDINAL_RESOLVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ORDINAL_RESOLVER, GOrdinalResolverClass))
#define G_IS_ORDINAL_RESOLVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ORDINAL_RESOLVER))
#define G_ORDINAL_RESOLVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ORDINAL_RESOLVER, GOrdinalResolverClass))
/* Tâche de résolution d'ordinaux (instance) */
typedef struct _GOrdinalResolver
{
GDelayedWork parent; /* A laisser en premier */
GPeFormat *format; /* Format à faire évoluer */
size_t begin; /* Point de départ du parcours */
size_t end; /* Point d'arrivée exclu */
activity_id_t id; /* Identifiant pour messages */
} GOrdinalResolver;
/* Tâche de résolution d'ordinaux (classe) */
typedef struct _GOrdinalResolverClass
{
GDelayedWorkClass parent; /* A laisser en premier */
} GOrdinalResolverClass;
/* Indique le type défini pour les tâches de résolution d'ordinaux. */
GType g_ordinal_resolver_get_type(void);
/* Initialise la classe des tâches des resolutions d'ordinaux. */
static void g_ordinal_resolver_class_init(GOrdinalResolverClass *);
/* Initialise une tâche de résolution d'ordinaux importés. */
static void g_ordinal_resolver_init(GOrdinalResolver *);
/* Supprime toutes les références externes. */
static void g_ordinal_resolver_dispose(GOrdinalResolver *);
/* Procède à la libération totale de la mémoire. */
static void g_ordinal_resolver_finalize(GOrdinalResolver *);
/* Crée une tâche de résolution des ordinaux importés. */
static GOrdinalResolver *g_ordinal_resolver_new(GPeFormat *, size_t, size_t, activity_id_t);
/* Effectue une résolution d'ordinaux importés. */
static void g_ordinal_resolver_process(GOrdinalResolver *, GtkStatusStack *);
/* Indique le type défini pour les tâches de résolution d'ordinaux. */
G_DEFINE_TYPE(GOrdinalResolver, g_ordinal_resolver, G_TYPE_DELAYED_WORK);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des tâches des resolutions d'ordinaux. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_ordinal_resolver_class_init(GOrdinalResolverClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GDelayedWorkClass *work; /* Version en classe parente */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_ordinal_resolver_dispose;
object->finalize = (GObjectFinalizeFunc)g_ordinal_resolver_finalize;
work = G_DELAYED_WORK_CLASS(klass);
work->run = (run_task_fc)g_ordinal_resolver_process;
}
/******************************************************************************
* *
* Paramètres : resolver = instance à initialiser. *
* *
* Description : Initialise une tâche de résolution d'ordinaux importés. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_ordinal_resolver_init(GOrdinalResolver *resolver)
{
resolver->format = NULL;
resolver->begin = 0;
resolver->end = 0;
resolver->id = 0;
}
/******************************************************************************
* *
* Paramètres : resolver = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_ordinal_resolver_dispose(GOrdinalResolver *resolver)
{
g_clear_object(&resolver->format);
G_OBJECT_CLASS(g_ordinal_resolver_parent_class)->dispose(G_OBJECT(resolver));
}
/******************************************************************************
* *
* Paramètres : resolver = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_ordinal_resolver_finalize(GOrdinalResolver *resolver)
{
G_OBJECT_CLASS(g_ordinal_resolver_parent_class)->finalize(G_OBJECT(resolver));
}
/******************************************************************************
* *
* Paramètres : format = ensemble d'instructions désassemblées. *
* begin = point de départ du parcours de liste. *
* end = point d'arrivée exclu du parcours. *
* id = identifiant du message affiché à l'utilisateur. *
* *
* Description : Crée une tâche de résolution des ordinaux importés. *
* *
* Retour : Tâche créée. *
* *
* Remarques : - *
* *
******************************************************************************/
static GOrdinalResolver *g_ordinal_resolver_new(GPeFormat *format, size_t begin, size_t end, activity_id_t id)
{
GOrdinalResolver *result; /* Tâche à retourner */
result = g_object_new(G_TYPE_ORDINAL_RESOLVER, NULL);
result->format = format;
g_object_ref(G_OBJECT(format));
result->begin = begin;
result->end = end;
result->id = id;
return result;
}
/******************************************************************************
* *
* Paramètres : resolver = étude de routines à mener. *
* status = barre de statut à tenir informée. *
* *
* Description : Effectue une résolution d'ordinaux importés. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_ordinal_resolver_process(GOrdinalResolver *resolver, GtkStatusStack *status)
{
GBinFormat *base; /* Format basique du binaire */
size_t i; /* Boucle de parcours */
GBinSymbol *symbol; /* Commodité d'accès */
uint16_t ordinal; /* Ordinal défini */
const char *name; /* Désignation actuelle */
const char *library; /* Fichier DLL à charger */
base = G_BIN_FORMAT(resolver->format);
for (i = resolver->begin; i < resolver->end; i++)
{
symbol = g_binary_format_get_symbol(base, i);
if (!G_IS_PE_IMPORTED_ROUTINE(symbol))
goto next;
ordinal = g_pe_exported_routine_get_ordinal(G_PE_EXPORTED_ROUTINE(symbol));
if (ordinal == UNDEF_PE_ORDINAL)
goto next;
name = g_binary_routine_get_name(G_BIN_ROUTINE(symbol));
if (name != NULL)
goto next;
library = g_pe_imported_routine_get_library(G_PE_IMPORTED_ROUTINE(symbol));
if (library == NULL)
goto next;
name = get_symbol_by_ordinal(library, ordinal);
if (name != NULL)
g_binary_routine_set_name(G_BIN_ROUTINE(symbol), strdup(name));
next:
gtk_status_stack_update_activity_value(status, resolver->id, 1);
g_object_unref(G_OBJECT(symbol));
}
}
/******************************************************************************
* *
* Paramètres : format = format PE à traiter. *
* status = barre de statut à tenir informée. *
* *
* Description : Attribue un nom aux symboles PE importés par ordinal. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void assign_name_imported_ordinals(GPeFormat *format, GtkStatusStack *status)
{
GBinFormat *base; /* Format basique du binaire */
size_t sym_count; /* Nombre de ces symboles */
guint runs_count; /* Qté d'exécutions parallèles */
size_t run_size; /* Volume réparti par exécution*/
activity_id_t id; /* Identifiant de progression */
GWorkQueue *queue; /* Gestionnaire de différés */
wgroup_id_t gid; /* Identifiant pour les tâches */
guint i; /* Boucle de parcours */
size_t begin; /* Début de bloc de traitement */
size_t end; /* Fin d'un bloc de traitement */
GOrdinalResolver *resolver; /* Tâche d'étude à programmer */
base = G_BIN_FORMAT(format);
g_binary_format_lock_symbols_rd(base);
sym_count = g_binary_format_count_symbols(base);
run_size = compute_run_size(sym_count, &runs_count);
id = gtk_status_stack_add_activity(status, _("Resolving names for imported ordinals..."), sym_count);
queue = get_work_queue();
gid = g_work_queue_define_work_group(queue);
for (i = 0; i < runs_count; i++)
{
begin = i * run_size;
if ((i + 1) == runs_count)
end = sym_count;
else
end = begin + run_size;
resolver = g_ordinal_resolver_new(format, begin, end, id);
g_work_queue_schedule_work(queue, G_DELAYED_WORK(resolver), gid);
}
g_work_queue_wait_for_completion(queue, gid);
g_work_queue_delete_work_group(queue, gid);
gtk_status_stack_remove_activity(status, id);
g_binary_format_unlock_symbols_rd(base);
}