summaryrefslogtreecommitdiff
path: root/plugins/lnxsyscalls
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-06-17 16:11:45 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-06-17 16:11:45 (GMT)
commit378be1ab322dce8e8377d692829d6877758e5960 (patch)
tree17dc518687a45649caa68304cc2a5750a0a50554 /plugins/lnxsyscalls
parent1f7e9506775f66a3a5f2859779d33b914eee8ef4 (diff)
Annotated linux kernel syscalls using a new plugin.
Diffstat (limited to 'plugins/lnxsyscalls')
-rw-r--r--plugins/lnxsyscalls/Makefile.am39
-rw-r--r--plugins/lnxsyscalls/collect.c643
-rw-r--r--plugins/lnxsyscalls/collect.h63
-rw-r--r--plugins/lnxsyscalls/core.c168
-rw-r--r--plugins/lnxsyscalls/core.h41
-rw-r--r--plugins/lnxsyscalls/db.c245
-rw-r--r--plugins/lnxsyscalls/db.h52
-rw-r--r--plugins/lnxsyscalls/hops.h67
-rw-r--r--plugins/lnxsyscalls/hops_armv7.c262
-rw-r--r--plugins/lnxsyscalls/hops_armv7.h37
-rw-r--r--plugins/lnxsyscalls/hunter.c346
-rw-r--r--plugins/lnxsyscalls/hunter.h56
-rw-r--r--plugins/lnxsyscalls/linux-syscalls.dbbin0 -> 49152 bytes
-rw-r--r--plugins/lnxsyscalls/syscall.c108
-rw-r--r--plugins/lnxsyscalls/syscall.h58
-rw-r--r--plugins/lnxsyscalls/writer.c222
-rw-r--r--plugins/lnxsyscalls/writer.h50
17 files changed, 2457 insertions, 0 deletions
diff --git a/plugins/lnxsyscalls/Makefile.am b/plugins/lnxsyscalls/Makefile.am
new file mode 100644
index 0000000..251c1c9
--- /dev/null
+++ b/plugins/lnxsyscalls/Makefile.am
@@ -0,0 +1,39 @@
+
+lib_LTLIBRARIES = liblnxsyscalls.la
+
+libdir = $(pluginsdir)
+
+
+liblnxsyscalls_la_SOURCES = \
+ collect.h collect.c \
+ core.h core.c \
+ db.h db.c \
+ hops.h \
+ hops_armv7.h hops_armv7.c \
+ hunter.h hunter.c \
+ syscall.h syscall.c \
+ writer.h writer.c
+
+liblnxsyscalls_la_CFLAGS = $(AM_CFLAGS)
+
+liblnxsyscalls_la_LIBADD =
+
+liblnxsyscalls_la_LDFLAGS = $(LIBPYTHON_LIBS) $(LIBPYGOBJECT_LIBS) \
+ -L$(top_srcdir)/src/.libs -lchrysacore
+
+
+db_DATA = linux-syscalls.db
+
+dbdir = $(pluginsdir)
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(liblnxsyscalls_la_SOURCES:%c=)
+
+
+AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+
+SUBDIRS =
diff --git a/plugins/lnxsyscalls/collect.c b/plugins/lnxsyscalls/collect.c
new file mode 100644
index 0000000..a71e833
--- /dev/null
+++ b/plugins/lnxsyscalls/collect.c
@@ -0,0 +1,643 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collect.c - collecte de différents registres en remontant le flot d'exécution
+ *
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "collect.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <arch/operands/register.h>
+
+
+#include "hops.h"
+
+
+
+/* Suivi de l'usage d'un registre */
+typedef struct _collected_register
+{
+ GArchRegister *reg; /* Registre usité à tracer */
+
+ bool required; /* Registre utile ? */
+
+ GArchInstruction *written; /* Emplacement d'écriture */
+
+} collected_register;
+
+/* Suivi d'un flot d'exécution */
+typedef struct _call_stack
+{
+ collected_register *registers; /* Liste de registres suivis */
+ size_t count; /* Taille de cette liste */
+
+ instr_iter_t *iter; /* Boucle de parcours */
+ bool use_current; /* Traite l'instruction pointée*/
+
+ bool skip_syscall; /* Acceptation des rencontres */
+
+} call_stack;
+
+/* Collection de registres */
+struct _tracked_path
+{
+ call_stack *stacks; /* Piles d'exécution suivies */
+ size_t count; /* Nombre de ces piles */
+
+};
+
+
+/* Copie les informations de pile d'appels. */
+static void copy_call_stack(call_stack *, const call_stack *);
+
+/* Libère la mémoire des infos relatives à une pile d'appels. */
+static void clean_call_stack(call_stack *);
+
+/* Fournit une structure de suivi de registres pour une branche. */
+static size_t fork_register_tracker(tracked_path *, size_t, GArchProcessor *, GArchInstruction *);
+
+/* Change la tête de lecture pour le parcours des instructions. */
+static void change_register_tracker_iter(tracked_path *, size_t, GArchProcessor *, GArchInstruction *);
+
+/* Détermine si tous les registres recherchés ont été trouvés. */
+static bool got_all_tracked_registers(const tracked_path *, size_t);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = zone de destination des données copiées. [OUT] *
+* src = source des données à copier. *
+* *
+* Description : Copie les informations de pile d'appels. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void copy_call_stack(call_stack *dest, const call_stack *src)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (src->count == 0)
+ {
+ dest->registers = NULL;
+ dest->count = 0;
+ }
+
+ else
+ {
+ dest->registers = (collected_register *)malloc(src->count * sizeof(collected_register));
+ dest->count = src->count;
+
+ for (i = 0; i < src->count; i++)
+ {
+ dest->registers[i].reg = src->registers[i].reg;
+ dest->registers[i].required = src->registers[i].required;
+ dest->registers[i].written = src->registers[i].written;
+
+ g_object_ref(G_OBJECT(dest->registers[i].reg));
+
+ if (dest->registers[i].written != NULL)
+ g_object_ref(G_OBJECT(dest->registers[i].written));
+
+ }
+
+ }
+
+ dest->iter = copy_instruction_iterator(src->iter);
+ dest->use_current = src->use_current;
+
+ dest->skip_syscall = src->skip_syscall;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = information sur une pile d'appels à supprimer. *
+* *
+* Description : Libère la mémoire des infos relatives à une pile d'appels. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void clean_call_stack(call_stack *stack)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < stack->count; i++)
+ {
+ g_object_unref(G_OBJECT(stack->registers[i].reg));
+
+ if (stack->registers[i].written != NULL)
+ g_object_unref(G_OBJECT(stack->registers[i].written));
+
+ }
+
+ if (stack->registers != NULL)
+ free(stack->registers);
+
+ if (stack->iter != NULL)
+ delete_instruction_iterator(stack->iter);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : base = position de parcours initiale. *
+* *
+* Description : Crée une structure de suivi de registres vide. *
+* *
+* Retour : Structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+tracked_path *create_register_tracker(instr_iter_t *base)
+{
+ tracked_path *result; /* Structure à retourner */
+
+ result = (tracked_path *)malloc(sizeof(tracked_path));
+
+ result->stacks = (call_stack *)malloc(sizeof(call_stack));
+ result->count = 1;
+
+ copy_call_stack(&result->stacks[0],
+ (call_stack []) {
+ {
+ .count = 0,
+ .iter = base,
+ .use_current = true,
+ .skip_syscall = true
+ }
+ });
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : model = suivi déjà en place d'où l'inspiration doit venir. *
+* sid = identifiant de la pile d'exécution initiale. *
+* *
+* Description : Crée une structure de suivi de registres initialisée. *
+* *
+* Retour : Structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+tracked_path *create_register_tracker_from(const tracked_path *model, size_t sid)
+{
+ tracked_path *result; /* Structure à retourner */
+
+ result = (tracked_path *)malloc(sizeof(tracked_path));
+
+ result->stacks = (call_stack *)malloc(sizeof(call_stack));
+ result->count = 1;
+
+ copy_call_stack(&result->stacks[0], &model->stacks[sid]);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à traiter. *
+* *
+* Description : Efface une structure de suivi de registres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_register_tracker(tracked_path *path)
+{
+ size_t i; /* Boucle de parcours */
+
+ assert(path->count >= 1);
+
+ for (i = 0; i < path->count; i++)
+ clean_call_stack(&path->stacks[i]);
+
+ free(path->stacks);
+
+ free(path);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à consulter. *
+* *
+* Description : Dénombre les piles d'exécutions différentes conservées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t count_register_tracker_stacks(const tracked_path *path)
+{
+ size_t result; /* Quantité à retourner */
+
+ result = path->count;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à traiter. *
+* sid = identifiant de la pile d'exécution racine à copier. *
+* proc = processeur de l'architecture pour les instructions. *
+* dest = prochaine instruction à traiter. *
+* *
+* Description : Fournit une structure de suivi de registres pour une branche.*
+* *
+* Retour : Indice de la nouvelle pile d'exécution à suivre. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static size_t fork_register_tracker(tracked_path *path, size_t sid, GArchProcessor *proc, GArchInstruction *dest)
+{
+ size_t result; /* Indice à retourner */
+
+ result = path->count;
+
+ path->stacks = (call_stack *)realloc(path->stacks, ++path->count * sizeof(call_stack));
+
+ copy_call_stack(&path->stacks[result], &path->stacks[sid]);
+
+ change_register_tracker_iter(path, result, proc, dest);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à traiter. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* proc = processeur de l'architecture pour les instructions. *
+* dest = prochaine instruction à traiter. *
+* *
+* Description : Change la tête de lecture pour le parcours des instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void change_register_tracker_iter(tracked_path *path, size_t sid, GArchProcessor *proc, GArchInstruction *dest)
+{
+ const mrange_t *range; /* Couverture d'une instruction*/
+ instr_iter_t *iter; /* Tête de lecture */
+
+ delete_instruction_iterator(path->stacks[sid].iter);
+
+ range = g_arch_instruction_get_range(dest);
+ iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(range));
+
+ path->stacks[sid].iter = iter;
+ path->stacks[sid].use_current = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à traiter. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* reg = registre concerné par la procédure. *
+* where = localisation de l'écriture ou importance de la note. *
+* *
+* Description : Note le besoin ou l'usage d'un registre donné. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void mark_register_in_tracker(tracked_path *path, size_t sid, GArchRegister *reg, GArchInstruction *where)
+{
+ call_stack *stack; /* Pile d'exécution concernée */
+ size_t i; /* Boucle de parcours */
+ collected_register *collected; /* Accès simplifié */
+ int ret; /* Bilan d'une comparaison */
+
+ stack = &path->stacks[sid];
+
+ /* Mise à jour d'un élément présent ? */
+
+ for (i = 0; i < stack->count; i++)
+ {
+ collected = &stack->registers[i];
+
+ ret = g_arch_register_compare(collected->reg, reg);
+ if (ret != 0) continue;
+
+ if (where == NULL)
+ collected->required = true;
+
+ else
+ {
+ if (collected->written == NULL)
+ {
+ collected->written = where;
+ g_object_ref(G_OBJECT(where));
+ }
+
+ }
+
+ break;
+
+ }
+
+ /* Ajout d'une nouvelle note */
+
+ if (i == stack->count)
+ {
+ stack->count++;
+ stack->registers = (collected_register *)realloc(stack->registers,
+ stack->count * sizeof(collected_register));
+
+ collected = &stack->registers[stack->count - 1];
+
+ collected->reg = reg;
+ g_object_ref(G_OBJECT(reg));
+
+ if (where == NULL)
+ {
+ collected->required = true;
+ collected->written = NULL;
+ }
+
+ else
+ {
+ collected->required = false;
+ collected->written = where;
+ g_object_ref(G_OBJECT(where));
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à consulter. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* *
+* Description : Détermine si tous les registres recherchés ont été trouvés. *
+* *
+* Retour : Besoin en poursuite d'études. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool got_all_tracked_registers(const tracked_path *path, size_t sid)
+{
+ bool result; /* Bilan à retourner */
+ call_stack *stack; /* Pile d'exécution concernée */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ stack = &path->stacks[sid];
+
+ for (i = 0; i < stack->count && result; i++)
+ if (stack->registers[i].required)
+ result = (stack->registers[i].written != NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à consulter et compléter. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* proc = processeur de l'architecture pour les instructions. *
+* hops = opérations spécialement adaptées à une architecture. *
+* *
+* Description : Se lance à la recherche de la définition de registres. *
+* *
+* Retour : true si toutes les définitions demandées ont été trouvées. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool look_for_registers(tracked_path *path, size_t sid, GArchProcessor *proc, const hunting_ops *hops)
+{
+ bool result; /* Bilan de l'opération */
+ call_stack *stack; /* Pile d'exécution concernée */
+ GArchInstruction *instr; /* Instruction analysée */
+ GArchOperand *operand; /* Destination d'instruction ? */
+ GArchRegister *reg; /* Registre en première ligne */
+ size_t count; /* Nombre de sources présentes */
+ bool first; /* Premier aiguillage ? */
+ size_t i; /* Boucle de parcours */
+ instr_link_t *link; /* Détails d'un lien */
+ size_t next; /* Indice de la pile suivante */
+
+ stack = &path->stacks[sid];
+
+ while (stack->iter != NULL && !got_all_tracked_registers(path, sid))
+ {
+ if (stack->use_current)
+ {
+ instr = get_instruction_iterator_current(stack->iter);
+ stack->use_current = false;
+ }
+
+ else
+ instr = get_instruction_iterator_prev(stack->iter);
+
+ /* Détection de fin de parcours (#1) */
+
+ if (instr == NULL)
+ {
+ delete_instruction_iterator(stack->iter);
+ stack->iter = NULL;
+ break;
+ }
+
+ if (hops->is_syscall(instr) && !stack->skip_syscall)
+ {
+ delete_instruction_iterator(stack->iter);
+ stack->iter = NULL;
+ break;
+ }
+
+ stack->skip_syscall = false;
+
+ /* Traitement de l'instruction courante */
+
+ operand = g_arch_instruction_get_operand(instr, 0);
+
+ if (G_IS_REGISTER_OPERAND(operand))
+ {
+ reg = g_register_operand_get_register(G_REGISTER_OPERAND(operand));
+
+ mark_register_in_tracker(path, sid, reg, instr);
+
+ }
+
+ /* Détermination de l'instruction suivante */
+
+ g_arch_instruction_lock_src(instr);
+
+ count = g_arch_instruction_count_sources(instr);
+
+ first = true;
+
+ for (i = 0; i < count; i++)
+ {
+ link = g_arch_instruction_get_source(instr, i);
+
+ switch (link->type)
+ {
+ case ILT_EXEC_FLOW:
+ case ILT_JUMP:
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
+ case ILT_LOOP:
+
+ if (first)
+ {
+ change_register_tracker_iter(path, sid, proc, link->linked);
+ first = false;
+ }
+
+ else
+ {
+ next = fork_register_tracker(path, sid, proc, link->linked);
+ look_for_registers(path, next, proc, hops);
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ g_arch_instruction_unlock_src(instr);
+
+ /* Détection de fin de parcours (#2) */
+
+ if (g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START)
+ {
+ delete_instruction_iterator(stack->iter);
+ stack->iter = NULL;
+ break;
+ }
+
+ }
+
+ result = got_all_tracked_registers(path, sid);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : path = chemin d'exécution à traiter. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* reg = registre concerné par la procédure. *
+* *
+* Description : Retrouve la dernière modification d'un registre donné. *
+* *
+* Retour : Localisation de l'écriture ou importante de la note. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GArchInstruction *get_register_write_location(const tracked_path *path, size_t sid, const GArchRegister *reg)
+{
+ GArchInstruction *result; /* Emplacement à retourner */
+ call_stack *stack; /* Pile d'exécution concernée */
+ size_t i; /* Boucle de parcours */
+ collected_register *collected; /* Accès simplifié */
+ int ret; /* Bilan d'une comparaison */
+
+ result = NULL;
+
+ stack = &path->stacks[sid];
+
+ for (i = 0; i < stack->count; i++)
+ {
+ collected = &stack->registers[i];
+
+ ret = g_arch_register_compare(collected->reg, reg);
+ if (ret != 0) continue;
+
+ result = collected->written;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/lnxsyscalls/collect.h b/plugins/lnxsyscalls/collect.h
new file mode 100644
index 0000000..370c27e
--- /dev/null
+++ b/plugins/lnxsyscalls/collect.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collect.h - prototypes pour la collecte de différents registres en remontant le flot d'exécution
+ *
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_COLLECT_H
+#define _PLUGINS_LNXSYSCALLS_COLLECT_H
+
+
+#include <arch/instriter.h>
+#include <arch/register.h>
+
+
+
+/* Depuis hops.h : opérations adaptées pour une chasse donnée */
+typedef struct _hunting_ops hunting_ops;
+
+/* Collection de registres */
+typedef struct _tracked_path tracked_path;
+
+
+/* Crée une structure de suivi de registres vide. */
+tracked_path *create_register_tracker(instr_iter_t *);
+
+/* Crée une structure de suivi de registres initialisée. */
+tracked_path *create_register_tracker_from(const tracked_path *, size_t);
+
+/* Efface une structure de suivi de registres. */
+void delete_register_tracker(tracked_path *);
+
+/* Dénombre les piles d'exécutions différentes conservées. */
+size_t count_register_tracker_stacks(const tracked_path *);
+
+/* Note le besoin ou l'usage d'un registre donné. */
+void mark_register_in_tracker(tracked_path *, size_t, GArchRegister *, GArchInstruction *);
+
+/* Se lance à la recherche de la définition de registres. */
+bool look_for_registers(tracked_path *, size_t, GArchProcessor *, const hunting_ops *);
+
+/* Retrouve la dernière modification d'un registre donné. */
+GArchInstruction *get_register_write_location(const tracked_path *, size_t, const GArchRegister *);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_COLLECT_H */
diff --git a/plugins/lnxsyscalls/core.c b/plugins/lnxsyscalls/core.c
new file mode 100644
index 0000000..f28e776
--- /dev/null
+++ b/plugins/lnxsyscalls/core.c
@@ -0,0 +1,168 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - greffon détaillant les appels système
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <i18n.h>
+
+
+#include <core/global.h>
+#include <core/nproc.h>
+
+
+#include "db.h"
+#include "hops_armv7.h"
+#include "hunter.h"
+
+
+
+DEFINE_CHRYSALIDE_PLUGIN("Linux System Calls", "Describes each Linux system call with its arguments", \
+ "0.1.0", EMPTY_PG_LIST(.required), AL(PGA_PLUGIN_INIT, PGA_DISASSEMBLY_ENDED));
+
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte du chargement du greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+{
+ bool result; /* Bilan à retourner */
+ sqlite3 *db; /* Base de données présente */
+
+ db = open_syscalls_database(plugin);
+
+ if (db != NULL)
+ {
+ introduce_syscalls_database(db, plugin);
+
+ close_syscalls_database(db);
+
+ result = true;
+
+ }
+
+ else
+ result = false;
+
+ return result;
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* action = type d'action attendue. *
+* binary = binaire dont le contenu est en cours de traitement.*
+* status = barre de statut à tenir informée. *
+* context = contexte de désassemblage. *
+* *
+* Description : Exécute une action pendant un désassemblage de binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT void process_binary_disassembly(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+{
+ GBinFormat *format; /* Format du binaire chargé */
+ const char *arch; /* Architecture d'exécution */
+ const hunting_ops *hops; /* Opérations particulières */
+ 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 */
+ GGateHunter *hunter; /* Tâche d'étude à programmer */
+
+ format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+ arch = g_exe_format_get_target_machine(G_EXE_FORMAT(format));
+
+ if (strcmp(arch, "armv7") == 0)
+ hops = get_armv7_hunting_ops();
+
+ else
+ {
+ g_plugin_module_log_variadic_message(plugin, LMT_WARNING,
+ _("No suitable backend to track syscalls!"));
+ goto pbd_exit;
+ }
+
+ g_binary_format_lock_symbols_rd(format);
+
+ sym_count = g_binary_format_count_symbols(format);
+
+ runs_count = get_max_online_threads();
+
+ run_size = sym_count / runs_count;
+
+ id = gtk_status_stack_add_activity(status, _("Looking for Linux syscalls..."), 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;
+
+ hunter = g_gate_hunter_new(plugin, binary, context, begin, end, id, hops);
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(hunter), 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(format);
+
+ pbd_exit:
+
+ g_object_unref(G_OBJECT(format));
+
+}
diff --git a/plugins/lnxsyscalls/core.h b/plugins/lnxsyscalls/core.h
new file mode 100644
index 0000000..a8e987e
--- /dev/null
+++ b/plugins/lnxsyscalls/core.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour le greffon détaillant les appels système
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_CORE_H
+#define _PLUGINS_LNXSYSCALLS_CORE_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+/* Prend acte du chargement du greffon. */
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+
+/* Exécute une action pendant un désassemblage de binaire. */
+G_MODULE_EXPORT void process_binary_disassembly(const GPluginModule *, PluginAction , GLoadedBinary *, GtkStatusStack *, GProcContext *);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_CORE_H */
diff --git a/plugins/lnxsyscalls/db.c b/plugins/lnxsyscalls/db.c
new file mode 100644
index 0000000..d6325b5
--- /dev/null
+++ b/plugins/lnxsyscalls/db.c
@@ -0,0 +1,245 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * db.c - constitution d'identités d'appels depuis une base de données
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "db.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include <i18n.h>
+
+
+#include <core/paths.h>
+#include <plugins/plugin-int.h>
+
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Ouvre la base de connaissances quant aux appels système. *
+* *
+* Retour : Base de données SQLite disponible ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+sqlite3 *open_syscalls_database(const GPluginModule *plugin)
+{
+ sqlite3 *result; /* Base de données à renvoyer */
+ char *filename; /* Chemin vers la base */
+ int ret; /* Bilan d'un appel */
+
+ filename = find_plugin_file("lnxsyscalls", "linux-syscalls.db");
+
+ if (filename == NULL)
+ {
+ g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("Unable to find the syscalls database"));
+ result = NULL;
+ }
+
+ else
+ {
+ ret = sqlite3_open(filename, &result);
+
+ if (ret != SQLITE_OK)
+ {
+ g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("Unable to load the syscalls database"));
+ result = NULL;
+ }
+
+ free(filename);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : db = base de données SQLite à clôturer. *
+* *
+* Description : Ferme la base de connaissances quant aux appels système. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void close_syscalls_database(sqlite3 *db)
+{
+#ifndef NDEBUG
+ int ret; /* Bilan d'un appel */
+#endif
+
+#ifndef NDEBUG
+
+ ret = sqlite3_close(db);
+ assert(ret == SQLITE_OK);
+
+#else
+
+ sqlite3_close(db);
+
+#endif
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : db = base de données SQLite à consulter. *
+* plugin = greffon à manipuler. *
+* *
+* Description : Présente le contenu de la base des appels système. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void introduce_syscalls_database(sqlite3 *db, const GPluginModule *plugin)
+{
+ const char *sql; /* Requête SQL à construire */
+ sqlite3_stmt *stmt; /* Déclaration mise en place */
+ int ret; /* Bilan d'un appel à SQLite */
+
+ sql = "SELECT arch, COUNT(nr) FROM Syscalls GROUP BY arch ORDER BY arch;";
+
+ ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ if (ret != SQLITE_OK)
+ {
+ g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+ _("Can't prepare statment '%s' (ret=%d): %s"),
+ sql, ret, sqlite3_errmsg(db));
+ goto isd_exit;
+ }
+
+ for (ret = sqlite3_step(stmt); ret == SQLITE_ROW; ret = sqlite3_step(stmt))
+ {
+ g_plugin_module_log_variadic_message(plugin, LMT_INFO,
+ _("The database contains %d syscalls for the '%s' architecture"),
+ sqlite3_column_int(stmt, 1),
+ (char *)sqlite3_column_text(stmt, 0));
+ }
+
+ sqlite3_finalize(stmt);
+
+ isd_exit:
+
+ ;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : db = base de données SQLite à consulter. *
+* plugin = greffon à manipuler. *
+* arch = architecture visée par la procédure. *
+* : nr = indice de l'appel système à décrire. *
+* *
+* Description : Construit l'identité d'un appel système pour un indice donné.*
+* *
+* Retour : Structure mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+syscall_info_t *extract_from_syscalls_database(sqlite3 *db, const GPluginModule *plugin, const char *arch, unsigned int nr)
+{
+ syscall_info_t *result; /* Description à retourner */
+ const char *sql; /* Requête SQL à construire */
+ size_t i; /* Boucle de parcours */
+ sqlite3_stmt *stmt; /* Déclaration mise en place */
+ int ret; /* Bilan d'un appel à SQLite */
+ const char *arg; /* Eventuel argument d'appel */
+
+ result = NULL;
+
+ sql = "SELECT name, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, filename, line" \
+ " FROM Syscalls" \
+ " WHERE arch = ? AND nr = ?;";
+
+ ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ if (ret != SQLITE_OK)
+ {
+ g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+ _("Can't prepare statment '%s' (ret=%d): %s"),
+ sql, ret, sqlite3_errmsg(db));
+ goto efsd_exit;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, arch, -1, NULL);
+ if (ret != SQLITE_OK)
+ {
+ g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+ _("Can't bind value for parameter nb 0 in '%s' (ret=%d): %s"),
+ sql, ret, sqlite3_errmsg(db));
+ goto efsd_clean_exit;
+ }
+
+ ret = sqlite3_bind_int(stmt, 2, nr);
+ if (ret != SQLITE_OK)
+ {
+ g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+ _("Can't bind value for parameter nb 1 in '%s' (ret=%d): %s"),
+ sql, ret, sqlite3_errmsg(db));
+ goto efsd_clean_exit;
+ }
+
+ ret = sqlite3_step(stmt);
+
+ if (ret == SQLITE_ROW)
+ {
+ result = create_syscall_info(nr, (char *)sqlite3_column_text(stmt, 0));
+
+ for (i = 0; i < 6; i++)
+ {
+ arg = (char *)sqlite3_column_text(stmt, 1 + i);
+
+ if (arg != NULL)
+ append_arg_to_syscall_info(result, arg);
+
+ }
+
+ }
+
+ efsd_clean_exit:
+
+ sqlite3_finalize(stmt);
+
+ efsd_exit:
+
+ return result;
+
+}
diff --git a/plugins/lnxsyscalls/db.h b/plugins/lnxsyscalls/db.h
new file mode 100644
index 0000000..7eae005
--- /dev/null
+++ b/plugins/lnxsyscalls/db.h
@@ -0,0 +1,52 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * db.h - prototypes pour la constitution d'identités d'appels depuis une base de données
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_DB_H
+#define _PLUGINS_LNXSYSCALLS_DB_H
+
+
+#include <sqlite3.h>
+
+
+#include <plugins/plugin.h>
+
+
+#include "syscall.h"
+
+
+
+/* Ouvre la base de connaissances quant aux appels système. */
+sqlite3 *open_syscalls_database(const GPluginModule *);
+
+/* Ferme la base de connaissances quant aux appels système. */
+void close_syscalls_database(sqlite3 *);
+
+/* Présente le contenu de la base des appels système. */
+void introduce_syscalls_database(sqlite3 *, const GPluginModule *);
+
+/* Construit l'identité d'un appel système pour un indice donné. */
+syscall_info_t *extract_from_syscalls_database(sqlite3 *, const GPluginModule *, const char *, unsigned int);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_DB_H */
diff --git a/plugins/lnxsyscalls/hops.h b/plugins/lnxsyscalls/hops.h
new file mode 100644
index 0000000..42f2cc6
--- /dev/null
+++ b/plugins/lnxsyscalls/hops.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hops.h - prototypes pour les particularités de chasse propres à une architecture
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_HOPS_H
+#define _PLUGINS_LNXSYSCALLS_HOPS_H
+
+
+#include <stdbool.h>
+
+
+#include <arch/processor.h>
+
+
+#include "collect.h"
+#include "syscall.h"
+#include "writer.h"
+
+
+
+/* Détermine si l'instruction lance un appel syystème. */
+typedef bool (* is_lsyscall_fc) (GArchInstruction *);
+
+/* Identifie le numéro d'appel système en cours de manipulation. */
+typedef bool (* resolve_lsyscall_nr_fc) (tracked_path *, GArchProcessor *, const hunting_ops *, unsigned int *);
+
+/* Marque les registres associés aux n premiers arguments. */
+typedef bool (* look_for_lsyscall_args_fc) (tracked_path *, size_t, size_t);
+
+/* Commente autant que possible un appel système brut. */
+typedef void (* comment_lsyscall_fc) (tracked_path *, size_t, syscall_info_t *, comment_writer *);
+
+
+/* Opérations adaptées pour une chasse donnée */
+typedef struct _hunting_ops
+{
+ const char *arch; /* Rappel de l'architecture */
+
+ is_lsyscall_fc is_syscall; /* Identification d'un appel */
+ resolve_lsyscall_nr_fc resolve_nr; /* Récupération d'un numéro */
+ look_for_lsyscall_args_fc look_for_args;/* Mise à prix de N arguments */
+ comment_lsyscall_fc comment; /* Inscription de commentaires */
+
+} hunting_ops;
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_HOPS_H */
diff --git a/plugins/lnxsyscalls/hops_armv7.c b/plugins/lnxsyscalls/hops_armv7.c
new file mode 100644
index 0000000..58b2702
--- /dev/null
+++ b/plugins/lnxsyscalls/hops_armv7.c
@@ -0,0 +1,262 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hops_armv7.c - recherche d'appels système spécifiques à ARMv7
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hops_armv7.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include <plugins/arm/v7/registers/basic.h>
+
+
+
+/* Détermine si l'instruction lance un appel syystème. */
+static bool is_armv7_linux_syscall(GArchInstruction *);
+
+/* Identifie le numéro d'appel système en cours de manipulation. */
+static bool resolve_armv7_linux_syscall_number(tracked_path *, GArchProcessor *, const hunting_ops *, unsigned int *);
+
+/* Marque les registres associés aux n premiers arguments. */
+static bool look_for_armv7_linux_syscall_args(tracked_path *, size_t, size_t);
+
+/* Commente autant que possible un appel système brut. */
+static void comment_armv7_linux_syscall(tracked_path *, size_t, syscall_info_t *, comment_writer *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit les opérations spécifiques à ARMv7 pour une chasse. *
+* *
+* Retour : Ensemble d'opérations pour une chasse aux appels système. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const hunting_ops *get_armv7_hunting_ops(void)
+{
+ static const hunting_ops armv7_hops = {
+
+ .arch = "arm",
+
+ .is_syscall = is_armv7_linux_syscall,
+ .resolve_nr = resolve_armv7_linux_syscall_number,
+ .look_for_args = look_for_armv7_linux_syscall_args,
+ .comment = comment_armv7_linux_syscall
+
+ };
+
+ return &armv7_hops;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction à analyser. *
+* *
+* Description : Détermine si l'instruction lance un appel syystème. *
+* *
+* Retour : Bilan de l'analyse : true s'il s'agit bien d'un appel. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool is_armv7_linux_syscall(GArchInstruction *instr)
+{
+ bool result; /* Conclusion à diffuser */
+ const char *kwd; /* Désignation d'instruction */
+
+ kwd = g_arch_instruction_get_keyword(instr, ASX_INTEL);
+
+ result = (strcmp(kwd, "svc") == 0);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : exec = suivi de l'utilisation des registres. *
+* proc = processeur de l'architecture pour les instructions. *
+* hops = opérations spécialement adaptées à une architecture. *
+* nr = numéro de l'appel système identifié. [OUT] *
+* *
+* Description : Identifie le numéro d'appel système en cours de manipulation.*
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool resolve_armv7_linux_syscall_number(tracked_path *exec, GArchProcessor *proc, const hunting_ops *hops, unsigned int *nr)
+{
+ bool result; /* Bilan à faire remonter */
+ GArchRegister *reg; /* Registre portant le numéro */
+ bool got_nr; /* Bilan d'une recherche */
+ GArchInstruction *instr; /* Instruction d'importance */
+ const char *kwd; /* Désignation d'instruction */
+ GArchOperand *op; /* Opérande avec une constante */
+
+ result = false;
+
+ /* On vise r7... */
+ reg = g_armv7_basic_register_new(7);
+ mark_register_in_tracker(exec, 0, reg, NULL);
+
+ assert(count_register_tracker_stacks(exec) == 1);
+
+ got_nr = look_for_registers(exec, 0, proc, hops);
+
+ if (got_nr)
+ {
+ instr = get_register_write_location(exec, 0, reg);
+ kwd = g_arch_instruction_get_keyword(instr, ASX_INTEL);
+
+ /* ... et uniquement les instructions 'mov r7, <imm>' */
+ if (strncmp(kwd, "mov", 3) != 0)
+ goto ralsn_exit;
+
+ op = g_arch_instruction_get_operand(instr, 1);
+
+ if (!G_IS_IMM_OPERAND(op))
+ goto ralsn_exit;
+
+ *nr = g_imm_operand_get_raw_value(G_IMM_OPERAND(op));
+ result = true;
+
+ }
+
+ ralsn_exit:
+
+ g_object_unref(G_OBJECT(reg));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : exec = chemin d'exécution à préparer. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* argc = nombre d'arguments à repérer. *
+* *
+* Description : Marque les registres associés aux n premiers arguments. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool look_for_armv7_linux_syscall_args(tracked_path *exec, size_t sid, size_t argc)
+{
+ bool result; /* Bilan à faire remonter */
+ size_t i; /* Boucle de parcours */
+ GArchRegister *reg; /* Registre portant le numéro */
+
+ /**
+ * man 2 syscall :
+ *
+ * arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7
+ * ──────────────────────────────────────────────────────────
+ * arm/OABI a1 a2 a3 a4 v1 v2 v3
+ * arm/EABI r0 r1 r2 r3 r4 r5 r6
+ */
+
+ result = (argc <= 7);
+
+ if (result)
+ for (i = 0; i < argc; i++)
+ {
+ reg = g_armv7_basic_register_new(i);
+ mark_register_in_tracker(exec, sid, reg, NULL);
+ g_object_ref(G_OBJECT(reg));
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : exec = chemin d'exécution identifié. *
+* sid = identifiant de la pile d'exécution à traiter. *
+* info = fiche d'identité d'un appel système. *
+* writer = conservateur des commentaires à écrire au final. *
+* *
+* Description : Commente autant que possible un appel système brut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void comment_armv7_linux_syscall(tracked_path *exec, size_t sid, syscall_info_t *info, comment_writer *writer)
+{
+ GArchRegister *reg; /* Registre intervenant */
+ GArchInstruction *instr; /* Instruction impliquée */
+ size_t i; /* Boucle de parcours */
+
+ /* Type d'appel système */
+
+ reg = g_armv7_basic_register_new(7);
+
+ instr = get_register_write_location(exec, sid, reg);
+
+ if (instr != NULL)
+ add_comment_at(writer, info->name, instr);
+
+ g_object_unref(G_OBJECT(instr));
+
+ g_object_unref(G_OBJECT(reg));
+
+ /* Eventuels arguments */
+
+ for (i = 0; i < info->argc; i++)
+ {
+ reg = g_armv7_basic_register_new(i);
+
+ instr = get_register_write_location(exec, sid, reg);
+
+ if (instr != NULL)
+ add_comment_at(writer, info->argv[i], instr);
+
+ g_object_unref(G_OBJECT(instr));
+
+ g_object_unref(G_OBJECT(reg));
+
+ }
+
+}
diff --git a/plugins/lnxsyscalls/hops_armv7.h b/plugins/lnxsyscalls/hops_armv7.h
new file mode 100644
index 0000000..a0dad87
--- /dev/null
+++ b/plugins/lnxsyscalls/hops_armv7.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hops_armv7.h - prototypes pour la recherche d'appels système spécifiques à ARMv7
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_HOPS_ARMV7_H
+#define _PLUGINS_LNXSYSCALLS_HOPS_ARMV7_H
+
+
+#include "hops.h"
+
+
+
+/* Fournit les opérations spécifiques à ARMv7 pour une chasse. */
+const hunting_ops *get_armv7_hunting_ops(void);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_HOPS_ARMV7_H */
diff --git a/plugins/lnxsyscalls/hunter.c b/plugins/lnxsyscalls/hunter.c
new file mode 100644
index 0000000..4cac8e6
--- /dev/null
+++ b/plugins/lnxsyscalls/hunter.c
@@ -0,0 +1,346 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hunter.c - recherche de portes vers le noyau
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hunter.h"
+
+
+#include <analysis/routine.h>
+#include <glibext/delayed-int.h>
+
+
+#include "db.h"
+
+
+
+/* Chasse à l'appel système (instance) */
+struct _GGateHunter
+{
+ GDelayedWork parent; /* A laisser en premier */
+
+ const GPluginModule *plugin; /* Liens pour les messages */
+
+ GLoadedBinary *binary; /* Binaire chargé et concerné */
+ GBinFormat *format; /* Format de fichier manipulé */
+ GProcContext *context; /* Contexte de désassemblage */
+
+ size_t begin; /* Point de départ du parcours */
+ size_t end; /* Point d'arrivée exclu */
+
+ activity_id_t id; /* Identifiant pour messages */
+
+ const hunting_ops *hops; /* Opérations particulières */
+ sqlite3 *db; /* Base de données à manipuler */
+
+};
+
+/* Chasse à l'appel système (classe) */
+struct _GGateHunterClass
+{
+ GDelayedWorkClass parent; /* A laisser en premier */
+
+};
+
+
+/* Indique le type défini pour les tâches d'étude de routines. */
+GType g_gate_hunter_get_type(void);
+
+/* Initialise la classe des tâches d'étude de routines. */
+static void g_gate_hunter_class_init(GGateHunterClass *);
+
+/* Initialise une tâche d'étude de routines. */
+static void g_gate_hunter_init(GGateHunter *);
+
+/* Supprime toutes les références externes. */
+static void g_gate_hunter_dispose(GGateHunter *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_gate_hunter_finalize(GGateHunter *);
+
+/* Effectue une recherche d'appels système. */
+static void g_gate_hunter_process(GGateHunter *, GtkStatusStack *);
+
+
+
+/* Indique le type défini pour les tâches d'étude de routines. */
+G_DEFINE_TYPE(GGateHunter, g_gate_hunter, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des tâches d'étude de routines. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gate_hunter_class_init(GGateHunterClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GDelayedWorkClass *work; /* Version en classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_gate_hunter_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_gate_hunter_finalize;
+
+ work = G_DELAYED_WORK_CLASS(klass);
+
+ work->run = (run_task_fc)g_gate_hunter_process;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : hunter = instance à initialiser. *
+* *
+* Description : Initialise une tâche d'étude de routines. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gate_hunter_init(GGateHunter *hunter)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : hunter = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gate_hunter_dispose(GGateHunter *hunter)
+{
+ g_object_unref(G_OBJECT(hunter->binary));
+
+ g_binary_format_unlock_symbols_rd(hunter->format);
+ g_object_unref(G_OBJECT(hunter->format));
+
+ g_object_unref(G_OBJECT(hunter->context));
+
+ G_OBJECT_CLASS(g_gate_hunter_parent_class)->dispose(G_OBJECT(hunter));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : hunter = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gate_hunter_finalize(GGateHunter *hunter)
+{
+ if (hunter->db != NULL)
+ close_syscalls_database(hunter->db);
+
+ G_OBJECT_CLASS(g_gate_hunter_parent_class)->finalize(G_OBJECT(hunter));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* binary = binaire dont la définition est à compléter. *
+* context = contexte de désassemblage. *
+* begin = point de départ du parcours de liste. *
+* end = point d'arrivée exclu du parcours. *
+* id = identifiant du message affiché à l'utilisateur. *
+* hops = opérations spécifiques à une architecture. *
+* *
+* Description : Crée une tâche de recherche de portes différée. *
+* *
+* Retour : Tâche créée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGateHunter *g_gate_hunter_new(const GPluginModule *plugin, GLoadedBinary *binary, GProcContext *context, size_t begin, size_t end, activity_id_t id, const hunting_ops *hops)
+{
+ GGateHunter *result; /* Tâche à retourner */
+
+ result = g_object_new(G_TYPE_GATE_HUNTER, NULL);
+
+ result->plugin = plugin;
+
+ result->binary = binary;
+ g_object_ref(G_OBJECT(binary));
+
+ result->format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+ g_binary_format_lock_symbols_rd(result->format);
+
+ result->context = context;
+ g_object_ref(G_OBJECT(context));
+
+ result->begin = begin;
+ result->end = end;
+
+ result->id = id;
+
+ result->hops = hops;
+
+ result->db = open_syscalls_database(plugin);
+ if (result->db == NULL) goto gghn_db_error;
+
+ return result;
+
+ gghn_db_error:
+
+ g_object_unref(G_OBJECT(result));
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : hunter = étude de routines à mener. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Effectue une recherche d'appels système. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gate_hunter_process(GGateHunter *hunter, GtkStatusStack *status)
+{
+ GArchProcessor *proc; /* Architecture du binaire */
+ size_t i; /* Boucle de parcours #1 */
+ GBinSymbol *symbol; /* Commodité d'accès */
+ const mrange_t *range; /* Couverture d'une routine */
+ instr_iter_t *iter; /* Boucle de parcours #2 */
+ GArchInstruction *instr; /* Instruction analysée */
+ tracked_path *exec; /* Chemin d'exécution à suivre */
+ unsigned int nr; /* Numéro d'appel système */
+ bool ret; /* Bilan d'un appel */
+ syscall_info_t *info; /* Information sur l'appel */
+ size_t loop; /* Quantité de boucles en vue */
+ size_t k; /* Boucle de parcours #3 */
+ comment_writer *writer; /* Ecriture de commentaires */
+
+ proc = g_loaded_binary_get_processor(hunter->binary);
+
+ for (i = hunter->begin; i < hunter->end; i++)
+ {
+ symbol = g_binary_format_get_symbol(hunter->format, i);
+
+ if (!G_IS_BIN_ROUTINE(symbol))
+ goto gghp_next;
+
+ range = g_binary_symbol_get_range(symbol);
+
+ iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(range));
+
+ if (iter != NULL)
+ {
+ restrict_instruction_iterator(iter, range);
+
+ for (instr = get_instruction_iterator_current(iter);
+ instr != NULL;
+ instr = get_instruction_iterator_next(iter))
+ {
+ if (hunter->hops->is_syscall(instr))
+ {
+ exec = create_register_tracker(iter);
+
+ ret = hunter->hops->resolve_nr(exec, proc, hunter->hops, &nr);
+ if (!ret) goto unknown_syscall;
+
+ info = extract_from_syscalls_database(hunter->db, hunter->plugin, hunter->hops->arch, nr);
+ if (info == NULL) goto unknown_syscall;
+
+ loop = count_register_tracker_stacks(exec);
+
+ for (k = 0; k < loop; k++)
+ {
+ ret = hunter->hops->look_for_args(exec, k, info->argc);
+ if (!ret) goto unknown_syscall;
+
+ look_for_registers(exec, k, proc, hunter->hops);
+
+ }
+
+ writer = create_comment_writer();
+
+ loop = count_register_tracker_stacks(exec);
+
+ for (k = 0; k < loop; k++)
+ hunter->hops->comment(exec, k, info, writer);
+
+ write_all_comments(writer, G_PRELOAD_INFO(hunter->context));
+
+ delete_comment_writer(writer);
+
+ unknown_syscall:
+
+ delete_register_tracker(exec);
+
+ }
+
+ g_object_unref(G_OBJECT(instr));
+
+ }
+
+ delete_instruction_iterator(iter);
+
+ }
+
+ gghp_next:
+
+ gtk_status_stack_update_activity_value(status, hunter->id, 1);
+
+ g_object_unref(G_OBJECT(symbol));
+
+ }
+
+ g_object_unref(G_OBJECT(proc));
+
+}
diff --git a/plugins/lnxsyscalls/hunter.h b/plugins/lnxsyscalls/hunter.h
new file mode 100644
index 0000000..100f426
--- /dev/null
+++ b/plugins/lnxsyscalls/hunter.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hunter.h - prototypes pour la recherche de portes vers le noyau
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_HUNTER_H
+#define _PLUGINS_LNXSYSCALLS_HUNTER_H
+
+
+#include <analysis/binary.h>
+#include <plugins/plugin.h>
+
+
+#include "hops.h"
+
+
+
+#define G_TYPE_GATE_HUNTER g_gate_hunter_get_type()
+#define G_GATE_HUNTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_gate_hunter_get_type(), GGateHunter))
+#define G_IS_GATE_HUNTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_gate_hunter_get_type()))
+#define G_GATE_HUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_GATE_HUNTER, GGateHunterClass))
+#define G_IS_GATE_HUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_GATE_HUNTER))
+#define G_GATE_HUNTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GATE_HUNTER, GGateHunterClass))
+
+
+/* Chasse à l'appel système (instance) */
+typedef struct _GGateHunter GGateHunter;
+
+/* Chasse à l'appel système (classe) */
+typedef struct _GGateHunterClass GGateHunterClass;
+
+
+/* Crée une tâche d'étude de routines différée. */
+GGateHunter *g_gate_hunter_new(const GPluginModule *, GLoadedBinary *, GProcContext *, size_t, size_t, activity_id_t, const hunting_ops *);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_HUNTER_H */
diff --git a/plugins/lnxsyscalls/linux-syscalls.db b/plugins/lnxsyscalls/linux-syscalls.db
new file mode 100644
index 0000000..c1ea339
--- /dev/null
+++ b/plugins/lnxsyscalls/linux-syscalls.db
Binary files differ
diff --git a/plugins/lnxsyscalls/syscall.c b/plugins/lnxsyscalls/syscall.c
new file mode 100644
index 0000000..e177d6e
--- /dev/null
+++ b/plugins/lnxsyscalls/syscall.c
@@ -0,0 +1,108 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * syscall.h - prototypes pour la définition d'appels système Linux
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "syscall.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+
+/******************************************************************************
+* *
+* Paramètres : nr = indice de l'appel système à décrire. *
+* name = désignation humaine de ce même appel système. *
+* *
+* Description : Crée un début de description d'appel système. *
+* *
+* Retour : Structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+syscall_info_t *create_syscall_info(unsigned int nr, const char *name)
+{
+ syscall_info_t *result; /* Description à retourner */
+
+ result = (syscall_info_t *)calloc(1, sizeof(syscall_info_t));
+
+ result->nr = nr;
+ result->name = strdup(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = description d'appel système à supprimer. *
+* *
+* Description : Efface de la mémoire une description d'appel système. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_syscall_info(syscall_info_t *info)
+{
+ size_t i; /* Boucle de parcours */
+
+ free(info->name);
+
+ for (i = 0; i < info->argc; i++)
+ free(info->argv[i]);
+
+ if (info->filename != NULL)
+ free(info->filename);
+
+ free(info);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = description d'appel système à compléter. *
+* arg = description d'un argument supplémentaire. *
+* *
+* Description : Ajoute un argument à une description d'appel système. *
+* *
+* Retour : Structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void append_arg_to_syscall_info(syscall_info_t *info, const char *arg)
+{
+ assert(info->argc < 6);
+
+ info->argv[info->argc++] = strdup(arg);
+
+}
diff --git a/plugins/lnxsyscalls/syscall.h b/plugins/lnxsyscalls/syscall.h
new file mode 100644
index 0000000..ecbe911
--- /dev/null
+++ b/plugins/lnxsyscalls/syscall.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * syscall.h - prototypes pour la définition d'appels système Linux
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_SYSCALL_H
+#define _PLUGINS_LNXSYSCALLS_SYSCALL_H
+
+
+#include <sys/types.h>
+
+
+
+/* Information quant à un appel */
+typedef struct _syscall_info_t
+{
+ unsigned int nr; /* Numéro de l'appel */
+ char *name; /* Désignation de l'appel */
+
+ size_t argc; /* Nombre d'arguments utilisés */
+ char *argv[6]; /* Argument possibles */
+
+ char *filename; /* Origine dans le code source */
+ unsigned int line; /* Numéro de ligne dans ce code*/
+
+} syscall_info_t ;
+
+
+/* Crée un début de description d'appel système. */
+syscall_info_t *create_syscall_info(unsigned int, const char *);
+
+/* Efface de la mémoire une description d'appel système. */
+void delete_syscall_info(syscall_info_t *);
+
+/* Ajoute un argument à une description d'appel système. */
+void append_arg_to_syscall_info(syscall_info_t *, const char *);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_SYSCALL_H */
diff --git a/plugins/lnxsyscalls/writer.c b/plugins/lnxsyscalls/writer.c
new file mode 100644
index 0000000..1263429
--- /dev/null
+++ b/plugins/lnxsyscalls/writer.c
@@ -0,0 +1,222 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * writer.c - mise en place de commentaires adaptés aux appels système
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "writer.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/db/items/comment.h>
+
+
+
+/* Empilement de commentaire à une adresse donnée */
+typedef struct _comment_data
+{
+ vmpa2t addr; /* Emplacement de l'insertion */
+
+ char **text; /* Pièces de texte rapportées */
+ size_t count; /* Nombre de ces pièces */
+
+} comment_data;
+
+/* Mémorisation des commentaires à insérer */
+struct _comment_writer
+{
+ comment_data *comments; /* Définitions de commentaire */
+ size_t count; /* Nombre de ces commentaires */
+
+};
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un espace de conservation pour commentaires d'appels. *
+* *
+* Retour : Structure de mémorisation en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+comment_writer *create_comment_writer(void)
+{
+ comment_writer *result; /* Structure à retourner */
+
+ result = (comment_writer *)malloc(sizeof(comment_writer));
+
+ result->comments = NULL;
+ result->count = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : writer = ensemble de commentaires conservés à supprimer. *
+* *
+* Description : Détruit la conservation de commentaires pour appels. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_comment_writer(comment_writer *writer)
+{
+ size_t i; /* Boucle de parcours #1 */
+ comment_data *data; /* Facilités d'accès */
+ size_t k; /* Boucle de parcours #2 */
+
+ for (i = 0; i < writer->count; i++)
+ {
+ data = &writer->comments[i];
+
+ for (k = 0; k < data->count; k++)
+ free(data->text[k]);
+
+ if (data->text != NULL)
+ free(data->text);
+
+ }
+
+ if (writer->comments != NULL)
+ free(writer->comments);
+
+ free(writer);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : writer = ensemble de commentaires conservés. *
+* text = commentaire humainement lisible à insérer. *
+* at = instruction dont l'adresse est la destination visée.*
+* *
+* Description : Complète un commentaire ou en insére un nouveau. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void add_comment_at(comment_writer *writer, const char *text, GArchInstruction *at)
+{
+ const mrange_t *range; /* Couverture d'une instruction*/
+ const vmpa2t *addr; /* Adresse de début liée */
+ size_t i; /* Boucle de parcours */
+ comment_data *target; /* Commentaire à éditer */
+ bool new; /* Age de ce commentaire */
+
+ range = g_arch_instruction_get_range(at);
+ addr = get_mrange_addr(range);
+
+ for (i = 0; i < writer->count; i++)
+ {
+ target = &writer->comments[i];
+
+ if (cmp_vmpa(addr, &target->addr) == 0)
+ break;
+
+ }
+
+ new = (i == writer->count);
+
+ if (new)
+ {
+ writer->comments = (comment_data *)realloc(writer->comments, ++writer->count * sizeof(comment_data));
+
+ target = &writer->comments[writer->count - 1];
+
+ copy_vmpa(&target->addr, addr);
+
+ target->text = NULL;
+ target->count = 0;
+
+ }
+
+ for (i = 0; i < target->count; i++)
+ if (strcmp(target->text[i], text) == 0)
+ break;
+
+ if (i == target->count)
+ {
+ target->text = (char **)realloc(target->text, ++target->count * sizeof(char *));
+
+ target->text[target->count - 1] = strdup(text);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : writer = ensemble de commentaires conservés. *
+* preload = contexte de désassemblage avec info préchargées. *
+* *
+* Description : Applique tous les commentaires à l'écriture anticipée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void write_all_comments(comment_writer *writer, GPreloadInfo *preload)
+{
+ size_t i; /* Boucle de parcours #1 */
+ comment_data *target; /* Commentaire à éditer */
+ GDbComment *comment; /* Commentaire final à intégrer*/
+ size_t k; /* Boucle de parcours #2 */
+
+ for (i = 0; i < writer->count; i++)
+ {
+ target = &writer->comments[i];
+
+ comment = g_db_comment_new_inlined(&target->addr, BLF_HAS_CODE, false);
+ g_db_item_set_volatile(G_DB_ITEM(comment), true);
+
+ for (k = 0; k < target->count; k++)
+ {
+ if (k > 0)
+ g_db_comment_add_static_text(comment, " / ");
+
+ g_db_comment_add_dynamic_text(comment, strdup(target->text[k]));
+
+ }
+
+ g_preload_info_add_comment(preload, comment);
+
+ }
+
+}
diff --git a/plugins/lnxsyscalls/writer.h b/plugins/lnxsyscalls/writer.h
new file mode 100644
index 0000000..113acda
--- /dev/null
+++ b/plugins/lnxsyscalls/writer.h
@@ -0,0 +1,50 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * writer.h - prototypes pour la mise en place de commentaires adaptés aux appels système
+ *
+ * Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_WRITER_H
+#define _PLUGINS_LNXSYSCALLS_WRITER_H
+
+
+#include <format/preload.h>
+
+
+
+/* Mémorisation des commentaires à insérer */
+typedef struct _comment_writer comment_writer;
+
+
+/* Crée un espace de conservation pour commentaires d'appels. */
+comment_writer *create_comment_writer(void);
+
+/* Détruit la conservation de commentaires pour appels. */
+void delete_comment_writer(comment_writer *);
+
+/* Complète un commentaire ou en insére un nouveau. */
+void add_comment_at(comment_writer *, const char *, GArchInstruction *);
+
+/* Applique tous les commentaires à l'écriture anticipée. */
+void write_all_comments(comment_writer *, GPreloadInfo *);
+
+
+
+#endif /* _PLUGINS_LNXSYSCALLS_WRITER_H */