diff options
Diffstat (limited to 'src/analysis/scan/patterns/tokens')
33 files changed, 8489 insertions, 0 deletions
diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am new file mode 100644 index 0000000..f0ab3d5 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/Makefile.am @@ -0,0 +1,26 @@ + +noinst_LTLIBRARIES = libanalysisscanpatternstokens.la + + +libanalysisscanpatternstokens_la_SOURCES = \ + atom.h atom.c \ + hex-int.h \ + hex.h hex.c \ + node-int.h \ + node.h node.c \ + offset.h offset.c \ + plain-int.h \ + plain.h plain.c + +libanalysisscanpatternstokens_la_LIBADD = \ + nodes/libanalysisscanpatternstokensnodes.la + +libanalysisscanpatternstokens_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatternstokens_la_SOURCES:%c=) + + +SUBDIRS = nodes diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c new file mode 100644 index 0000000..4f2ad67 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/atom.c @@ -0,0 +1,543 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * atom.c - détermination d'atomes à partir de motifs + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "atom.h" + + +#include <assert.h> +#include <malloc.h> +#include <math.h> + + + +/** + * Remplacement des fonctions de <ctypes.h> dans support des locales. + */ + +#define IS_CH_LETTER(ch) (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z')) + +#define MAKE_CH_UPPER(ch) (ch & 0xdf) +#define MAKE_CH_LOWER(ch) (ch | 0x20) + + + +/****************************************************************************** +* * +* Paramètres : ch = octet dont la valeur est à analyser. * +* seen = suivi des octets déjà rencontrés. [OUT] * +* uniq = volume d'octets originaux à actualiser. [OUT] * +* letters = nombre de lettres rencontrées. [OUT] * +* * +* Description : Note l'intêret de rechercher un octet particulier. * +* * +* Retour : Note positive ou négative. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int rate_byte_quality(bin_t ch, uint8_t *seen, size_t *uniq, size_t *letters) +{ + int result; /* Note à retourner */ + + switch (ch) + { + case 0x00: + case 0x20: + case 0x90: + case 0xcc: + case 0xff: + result = 12; + break; + + case 'A' ... 'Z': + case 'a' ... 'z': + if (letters == NULL) + result = 20; + else + { + result = 18; + (*letters)++; + } + break; + + default: + result = 20; + break; + + } + + if (seen[ch]++ == 0) + (*uniq)++; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : ch = octet dont la valeur est à analyser. * +* seen = suivi des octets déjà rencontrés. [OUT] * +* uniq = volume d'octets originaux à actualiser. [OUT] * +* letters = nombre de lettres rencontrées. [OUT] * +* * +* Description : Annihile l'intêret de rechercher un octet particulier. * +* * +* Retour : Note positive ou négative. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int unrate_byte_quality(bin_t ch, uint8_t *seen, size_t *uniq, size_t *letters) +{ + int result; /* Note à retourner */ + + switch (ch) + { + case 0x00: + case 0x20: + case 0x90: + case 0xcc: + case 0xff: + result = 12; + break; + + case 'A' ... 'Z': + case 'a' ... 'z': + if (letters == NULL) + result = 20; + else + { + result = 18; + assert(*letters > 0); + (*letters)--; + } + break; + + default: + result = 20; + break; + + } + + if (--seen[ch] == 0) + { + assert(*uniq > 0); + (*uniq)--; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rating = note d'évaluation courante. * +* uniq = volume d'octets originaux relevés. * +* max = nombre d'octets considérés à la base. * +* * +* Description : Termine la notation d'un ensemble d'octets. * +* * +* Retour : Note positive ou négative. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int finish_quality_rating(int rating, size_t uniq, size_t max) +{ + int result; /* Note à retourner */ + bool bad; /* Indice de mauvaise qualité */ + + if (uniq == 1) + { + bad = (rating % 12) == 0; + + result = (bad ? -10 * max : 2); + + } + + else + result = uniq * 2; + + result += rating; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = définition de la bribe à enregistrer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* atom = informations de suivi constituées. [OUT] * +* letters = nombre de lettres rencontrées. [OUT] * +* * +* Description : Détermine la portion idéale de recherche. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom_t *atom, size_t *letters) +{ + size_t i; /* Boucle de parcours #1 */ + bin_t ch; /* Octets à étudier */ + size_t best_letters; /* Mémorisation de décompte */ + size_t *ptr_letters; /* Pointeur vers le décompte */ + int raw_rating; /* Notation brute de séquence */ + uint8_t seen[256]; /* Mémorisation des passages */ + size_t uniq; /* Nombre d'octets originaux */ + const bin_t *last; /* Dernier caractère étudié */ + int best_rating; /* Meilleur notation obtenue */ + size_t max_loop; /* Limitation des itérations */ + size_t k; /* Boucle de parcours #2 */ + size_t local_letters; /* Décompte courant des lettres*/ + int local_rating; /* Notation courante */ + const bin_t *first; /* Premier caractère étudié */ + + /* Si la chaîne fournie est plus petite que la taille d'un atome... */ + if (raw->len <= maxsize) + { + atom->pos = 0; + atom->len = raw->len; + atom->rem = 0; + + atom->fast_check = true; + + if (letters != NULL) + { + *letters = 0; + + for (i = 0; i < raw->len; i++) + { + ch = raw->data[i]; + + if (IS_CH_LETTER(ch)) + (*letters)++; + + } + + } + + } + + /* ... ou si une sélection doit s'opérer */ + else + { + /* Etablissement d'une mesure de référence à la position 0 */ + + atom->pos = 0; + atom->len = maxsize; + + ptr_letters = (letters != NULL ? &best_letters : NULL); + + best_letters = 0; + raw_rating = 0; + + memset(seen, 0, sizeof(seen)); + uniq = 0; + + last = raw->static_bin_data; + + for (k = 0; k < maxsize; k++) + raw_rating += rate_byte_quality(*last++, seen, &uniq, ptr_letters); + + best_rating = finish_quality_rating(raw_rating, uniq, maxsize); + + /* Parcours du reste du contenu */ + + max_loop = (raw->len - maxsize); + + ptr_letters = (letters != NULL ? &local_letters : NULL); + + local_letters = best_letters; + local_rating = best_rating; + + first = raw->static_bin_data; + + for (i = 0; i < max_loop; i++) + { + raw_rating += rate_byte_quality(*last++, seen, &uniq, ptr_letters); + raw_rating -= unrate_byte_quality(*first++, seen, &uniq, ptr_letters); + + local_rating = finish_quality_rating(raw_rating , uniq, maxsize); + + if (local_rating > best_rating) + { + atom->pos = i + 1; + + best_letters = local_letters; + best_rating = local_rating; + + } + + } + + /* Conclusion */ + + atom->rem = raw->len - atom->pos - maxsize; + + atom->fast_check = false; + + if (letters != NULL) + *letters = best_letters; + + } + + assert((atom->fast_check && atom->pos == 0 && atom->rem == 0) + || (!atom->fast_check && (atom->pos != 0 || atom->rem != 0))); + +} + + +/****************************************************************************** +* * +* Paramètres : src = chaîne ed référence à dupliquer. * +* atom = préselection opérée en amont. * +* count = nombre de lettres présentes. * +* * +* Description : Etablit la liste des cas de figures ignorant la casse. * +* * +* Retour : Liste de toutes les combinaisons possibles. * +* * +* Remarques : - * +* * +******************************************************************************/ + +sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, const tracked_scan_atom_t *atom, size_t count) +{ + sized_binary_t *result; /* Liste à retourner */ + size_t i; /* Boucle de parcours #1 */ + size_t replaced; /* 2^(alternatives créées) */ +#ifndef NDEBUG + size_t check; /* Validation du compte max. */ +#endif + bin_t ch; /* Octet à recopier */ + size_t k; /* Boucle de parcours #2 */ + size_t divisor; /* Taille de la découpe */ + size_t quotient; /* Reste de la position */ + + /* Création du réceptacle */ + + result = malloc(count * sizeof(tracked_scan_atom_t)); + + assert(src->len == (atom->pos + atom->len + atom->rem)); + + for (i = 0; i < count; i++) + { + result[i].data = malloc(src->len); + result[i].len = src->len; + + memcpy(result[i].data, src->data, atom->pos); + memcpy(&result[i].data[atom->pos + atom->len], &src->data[atom->pos + atom->len], atom->rem); + + } + + /* Remplissage */ + + replaced = 2; + +#ifndef NDEBUG + check = 1; +#endif + + for (i = atom->pos; i < (atom->pos + atom->len); i++) + { + ch = src->data[i]; + + if (IS_CH_LETTER(ch)) + { + for (k = 0; k < count; k++) + { + divisor = count / replaced; + quotient = k / divisor; + + if ((quotient % 2) == 0) + result[k].data[i] = MAKE_CH_UPPER(ch); + else + result[k].data[i] = MAKE_CH_LOWER(ch); + + } + + replaced *= 2; + +#ifndef NDEBUG + check *= 2; + assert(check <= count); +#endif + + } + else + for (k = 0; k < count; k++) + result[k].data[i] = ch; + + } + + assert(check == count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = octets partiels avec leur masque à interpréter. * +* len = quantité d'octets à interpréter. * +* produced = nombre de contenus générés. [OUT] * +* * +* Description : Etablit la liste des cas de figures avec des octets partiels.* +* * +* Retour : Liste de toutes les combinaisons possibles. * +* * +* Remarques : - * +* * +******************************************************************************/ + +sized_binary_t *make_atoms_from_masked_bytes(const masked_byte_t *bytes, size_t len, size_t *produced) +{ + sized_binary_t *result; /* Liste à retourner */ + size_t seq_len; /* Taille de séquence retenue */ + size_t repeat_times; /* Répétitions pour remplissage*/ + sized_binary_t *maxiter; /* Borne de fin de parcours */ + size_t i; /* Boucle de parcours #1 */ + sized_binary_t *iter; /* Boucle de parcours #2 */ + size_t j; /* Boucle de parcours #3 */ + size_t k; /* Boucle de parcours #4 */ + + seq_len = (len > MASK_MAX_LEN_FOR_ATOMS ? MASK_MAX_LEN_FOR_ATOMS : len); + + /** + * Si l'usage de la fonction pow() disparaît, la bibliothèque m + * peut être retirée de libchrysacore_la_LDFLAGS dans le Makefile + * principal. + */ + repeat_times = pow(16, seq_len - 1); + + *produced = 16 * repeat_times; + + /* Création du réceptacle */ + + result = malloc(*produced * sizeof(tracked_scan_atom_t)); + + maxiter = result + *produced; + + /* Remplissage */ + + for (i = 0; i < seq_len; i++) + { + for (iter = result; iter < maxiter; ) + { + for (j = 0; j < 16; j++) + { + assert(bytes[i].mask == 0x0f || bytes[i].mask == 0xf0); + + for (k = 0; k < repeat_times; k++) + { + if (i == 0) + { + iter->data = malloc(seq_len); + iter->len = seq_len; + } + + if (bytes[i].mask == 0x0f) + iter->data[i] = bytes[i].value | (j << 4); + else + iter->data[i] = bytes[i].value | j; + + iter++; + + } + + } + + } + + repeat_times /= 16; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* atom = informations de suivi constituées. [OUT] * +* * +* Description : Amorce l'insertion de l'atome déterminé d'une série d'octets.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool enroll_prepared_atom(const sized_binary_t *raw, GEngineBackend *backend, tracked_scan_atom_t *atom) +{ + bool result; /* Statut à retourner */ + const bin_t *data; /* Données à rechercher */ + + data = raw->static_bin_data + atom->pos; + + result = g_engine_backend_enroll_plain_pattern(backend, data, atom->len, atom->tmp_id); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : atom = informations de suivi constituées. [OUT] * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool build_atom_pattern_id(tracked_scan_atom_t *atom, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + + atom->pid = g_engine_backend_build_plain_pattern_id(backend, atom->tmp_id); + + result = (atom->pid != INVALID_PATTERN_ID); + + return result; + +} diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h new file mode 100644 index 0000000..1ef8f40 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/atom.h @@ -0,0 +1,88 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * atom.h - prototypes pour la détermination d'atomes à partir de motifs + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H + + +#include <stdbool.h> + + +#include "../backend.h" +#include "../../../../arch/vmpa.h" +#include "../../../../common/szstr.h" + + + +/* Suivi des motifs réellement recherchés */ +typedef struct _tracked_scan_atom_t +{ + phys_t pos; /* Début de sélection atomique */ + phys_t len; /* Taille de ladite sélection */ + phys_t rem; /* Reste après l'atome */ + + bool fast_check; /* Besoin de vérifications ? */ + + uint32_t tmp_id[2]; /* Couple d'identifiants temp. */ + + patid_t pid; /* Identifiant de la bribe */ + +} tracked_scan_atom_t; + +/* Note l'intêret de rechercher un octet particulier. */ +int rate_byte_quality(bin_t, uint8_t *, size_t *, size_t *); + +/* Annihile l'intêret de rechercher un octet particulier. */ +int unrate_byte_quality(bin_t, uint8_t *, size_t *, size_t *); + +/* Termine la notation d'un ensemble d'octets. */ +int finish_quality_rating(int, size_t, size_t); + +/* Détermine la portion idéale de recherche. */ +void find_best_atom(const sized_binary_t *, size_t , tracked_scan_atom_t *, size_t *); + +/* Etablit la liste des cas de figures ignorant la casse. */ +sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, const tracked_scan_atom_t *, size_t); + +/* Mémorisation d'un octet visé avec son masque */ +typedef struct _masked_byte_t +{ + bin_t value; /* Valeur de l'octet visé */ + bin_t mask; /* Masque à appliquer */ + +} masked_byte_t; + +#define MASK_MAX_LEN_FOR_ATOMS 2 + +/* Etablit la liste des cas de figures avec des octets partiels. */ +sized_binary_t *make_atoms_from_masked_bytes(const masked_byte_t *, size_t, size_t *); + +/* Amorce l'insertion de l'atome déterminé d'une série d'octets. */ +bool enroll_prepared_atom(const sized_binary_t *, GEngineBackend *, tracked_scan_atom_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +bool build_atom_pattern_id(tracked_scan_atom_t *, GEngineBackend *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H */ diff --git a/src/analysis/scan/patterns/tokens/hex-int.h b/src/analysis/scan/patterns/tokens/hex-int.h new file mode 100644 index 0000000..dca9848 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/hex-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex-int.h - prototypes internes pour la recherche de morceaux de binaire + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H + + +#include "hex.h" + + +#include "atom.h" +#include "../token-int.h" + + + +/* Encadrement d'une recherche de morceaux de binaire (instance) */ +struct _GScanHexBytes +{ + GBytesToken parent; /* A laisser en premier */ + +}; + +/* Encadrement d'une recherche de morceaux de binaire (classe) */ +struct _GScanHexBytesClass +{ + GBytesTokenClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un gestionnaire de recherche de binaire. */ +bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *, bool); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/hex.c b/src/analysis/scan/patterns/tokens/hex.c new file mode 100644 index 0000000..89d7ca4 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/hex.c @@ -0,0 +1,259 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - recherche de morceaux de binaire + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "hex.h" + + +#include <malloc.h> +#include <string.h> + + +#include "hex-int.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des recherches de texte brut. */ +static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass); + +/* Initialise une instance de recherche de texte brut. */ +static void g_scan_hex_bytes_init(GScanHexBytes *); + +/* Supprime toutes les références externes. */ +static void g_scan_hex_bytes_dispose(GScanHexBytes *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_hex_bytes_finalize(GScanHexBytes *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Affiche un motif de recherche au format texte. */ +static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *, GScanContext *, int); + +/* Affiche un motif de recherche au format JSON. */ +static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *, GScanContext *, const sized_string_t *, unsigned int, int); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +G_DEFINE_TYPE(GScanHexBytes, g_scan_hex_bytes, G_TYPE_BYTES_TOKEN); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des recherches de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GSearchPatternClass *pattern; /* Version de classe ancêtre */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_hex_bytes_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_hex_bytes_finalize; + + pattern = G_SEARCH_PATTERN_CLASS(klass); + + pattern->to_text = (output_pattern_to_text_fc)g_scan_hex_bytes_output_to_text; + pattern->to_json = (output_pattern_to_json_fc)g_scan_hex_bytes_output_to_json; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance à initialiser. * +* * +* Description : Initialise une instance de recherche de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_init(GScanHexBytes *bytes) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_dispose(GScanHexBytes *bytes) +{ + G_OBJECT_CLASS(g_scan_hex_bytes_parent_class)->dispose(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes) +{ + G_OBJECT_CLASS(g_scan_hex_bytes_parent_class)->finalize(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : root = représentation du motif à recherche. * +* private = donne une vocation privée au motif de recherche. * +* * +* Description : Construit un gestionnaire de recherche de texte brut. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root, bool private) +{ + GSearchPattern *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_HEX_BYTES, NULL); + + if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root, private)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = encadrement de motif à initialiser pleinement. * +* root = représentation du motif à recherche. * +* private = donne une vocation privée au motif de recherche. * +* * +* Description : Met en place un gestionnaire de recherche de binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root, bool private) +{ + bool result; /* Bilan à retourner */ + + result = g_bytes_token_create(G_BYTES_TOKEN(bytes), root, false, private); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *pattern, GScanContext *context, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_hex_bytes_parent_class)->to_text(G_SEARCH_PATTERN(pattern), context, fd); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_hex_bytes_parent_class)->to_json(G_SEARCH_PATTERN(pattern), context, padding, level, fd); + + /* TODO */ + +} diff --git a/src/analysis/scan/patterns/tokens/hex.h b/src/analysis/scan/patterns/tokens/hex.h new file mode 100644 index 0000000..fe5268c --- /dev/null +++ b/src/analysis/scan/patterns/tokens/hex.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.h - prototypes pour la recherche de morceaux de binaire + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H + + +#include <glib-object.h> + + +#include "node.h" +#include "../../pattern.h" + + + +#define G_TYPE_SCAN_HEX_BYTES g_scan_hex_bytes_get_type() +#define G_SCAN_HEX_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_HEX_BYTES, GScanHexBytes)) +#define G_IS_SCAN_HEX_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_HEX_BYTES)) +#define G_SCAN_HEX_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_HEX_BYTES, GScanHexBytesClass)) +#define G_IS_SCAN_HEX_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_HEX_BYTES)) +#define G_SCAN_HEX_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_HEX_BYTES, GScanHexBytesClass)) + + +/* Encadrement d'une recherche de morceaux de binaire (instance) */ +typedef struct _GScanHexBytes GScanHexBytes; + +/* Encadrement d'une recherche de morceaux de binaire (classe) */ +typedef struct _GScanHexBytesClass GScanHexBytesClass; + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +GType g_scan_hex_bytes_get_type(void); + +/* Construit un gestionnaire de recherche de texte brut. */ +GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *, bool); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H */ diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h new file mode 100644 index 0000000..520e2a4 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/node-int.h @@ -0,0 +1,108 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node-int.h - prototypes internes pour la décomposition d'un motif de recherche en atomes assemblés + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H + + +#include "node.h" + + + +/* Communique l'intérêt d'un noeud au sein d'une analyse. */ +typedef float (* compute_scan_token_node_weight_fc) (const GScanTokenNode *); + +/* Prend acte d'une nouvelle propriété pour le noeud. */ +typedef void (* apply_scan_token_node_flags_fc) (GScanTokenNode *, ScanTokenNodeFlags); + +/* Noeuds clefs de l'arborescence mise en place */ +typedef struct _scan_tree_points_t +{ + GScanTokenNode *first_plain; /* Premier noeud textuel */ + GScanTokenNode *best_masked; /* Noeud masqué le plus long */ + +} scan_tree_points_t; + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +typedef void (* visit_scan_token_node_fc) (GScanTokenNode *, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +typedef bool (* build_scan_token_node_id_fc) (GScanTokenNode *, GEngineBackend *); + +typedef enum _TokenNodeCheckFlags +{ + TNCF_UPDATE_IN_PLACE = (1 << 0), /* Actualisation de l'entrée */ + TNCF_CREATE_NEW = (1 << 1), /* Allocation de positions */ + TNCF_KEEP_DISCARDED = (1 << 2), /* Inversion des résultats */ + +} TokenNodeCheckFlags; + +/* Transforme les correspondances locales en trouvailles. */ +typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + +/* Décomposition d'un motif de recherche en atomes (instance) */ +struct _GScanTokenNode +{ + GObject parent; /* A laisser en premier */ + + ScanTokenNodeFlags flags; /* Propriétés particulières */ + +}; + +/* Décomposition d'un motif de recherche en atomes (classe) */ +struct _GScanTokenNodeClass +{ + GObjectClass parent; /* A laisser en premier */ + + compute_scan_token_node_weight_fc compute_weight; /* Evaluation */ + visit_scan_token_node_fc visit; /* Phase de répérage initial */ + apply_scan_token_node_flags_fc apply; /* Prise en compte de fanions */ + + enroll_scan_token_node_fc enroll; /* Inscription d'un motif */ + build_scan_token_node_id_fc build_id; /* Récupération d'identifiant */ + + check_scan_token_node_fc check_forward; /* Conversion en trouvailles */ + check_scan_token_node_fc check_backward;/* Conversion en trouvailles */ + +}; + + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +void g_scan_token_node_visit(GScanTokenNode *, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +bool _g_scan_token_node_enroll(GScanTokenNode *, GEngineBackend *, size_t, size_t *); + +/* Transforme les correspondances locales en trouvailles. */ +void _g_scan_token_node_check_forward(const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +void _g_scan_token_node_check_backward(const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/node.c b/src/analysis/scan/patterns/tokens/node.c new file mode 100644 index 0000000..767cc6d --- /dev/null +++ b/src/analysis/scan/patterns/tokens/node.c @@ -0,0 +1,675 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.c - décomposition d'un motif de recherche en atomes assemblés + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "node.h" + + +#include <assert.h> + + +#include "node-int.h" +#include "nodes/any.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des éléments de décomposition. */ +static void g_scan_token_node_class_init(GScanTokenNodeClass *); + +/* Initialise une instance d'élément décomposant un motif. */ +static void g_scan_token_node_init(GScanTokenNode *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_dispose(GScanTokenNode *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_finalize(GScanTokenNode *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */ +G_DEFINE_TYPE(GScanTokenNode, g_scan_token_node, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des éléments de décomposition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_class_init(GScanTokenNodeClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance à initialiser. * +* * +* Description : Initialise une instance d'élément décomposant un motif. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_init(GScanTokenNode *node) +{ + node->flags = STNF_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_dispose(GScanTokenNode *node) +{ + G_OBJECT_CLASS(g_scan_token_node_parent_class)->dispose(G_OBJECT(node)); + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_finalize(GScanTokenNode *node) +{ + G_OBJECT_CLASS(g_scan_token_node_parent_class)->finalize(G_OBJECT(node)); + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à consulter. * +* * +* Description : Communique l'intérêt d'un noeud au sein d'une analyse. * +* * +* Retour : Poids de l'importance pour un départ de scan. * +* * +* Remarques : - * +* * +******************************************************************************/ + +float g_scan_token_node_compute_weight_for_scan(const GScanTokenNode *node) +{ + float result; /* Valeur à retourner */ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + if (class->compute_weight != NULL) + result = class->compute_weight(node); + else + result = 0; + + return result; + +} + + + + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à consulter. * +* * +* Description : Indique les propriétés particulières d'un noeud d'analyse. * +* * +* Retour : Propriétés particulières associées au noeud. * +* * +* Remarques : - * +* * +******************************************************************************/ + +ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *node) +{ + ScanTokenNodeFlags result; /* Statut à retourner */ + + result = node->flags; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à mettre à jour. * +* flags = propriétés particulières à associer au noeud. * +* * +* Description : Marque le noeud avec des propriétés particulières. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_set_flags(GScanTokenNode *node, ScanTokenNodeFlags flags) +{ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + node->flags |= flags; + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + if (class->apply != NULL) + class->apply(node, flags); + +} + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à effectuer. * +* points = points capitaux de l'arborescence. [OUT] * +* * +* Description : Parcourt une arborescence de noeuds et y relève des éléments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_visit(GScanTokenNode *node, scan_tree_points_t *points) +{ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + if (class->visit != NULL) + class->visit(node, points); + +} + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à préparer. * +* * +* Description : Détermine et prépare les éléments clefs d'une arborescence. * +* * +* Retour : true si une analyse à rebourd complémentaire est requise. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_setup_tree(GScanTokenNode *node) +{ + bool result; /* Prévision à retourner */ + scan_tree_points_t points; /* Repérage de points capitaux */ + GScanTokenNode *main; /* Principal noeud d'opération */ + + /* Phase de localisation */ + + points.first_plain = NULL; + points.best_masked = NULL; + + g_scan_token_node_visit(node, &points); + + /* Phase d'application */ + + g_scan_token_node_set_flags(node, STNF_FIRST); + g_scan_token_node_set_flags(node, STNF_LAST); + + if (points.first_plain != NULL) + main = points.first_plain; + + else if (points.best_masked != NULL) + main = points.best_masked; + + else + main = node; + + g_scan_token_node_set_flags(main, STNF_MAIN); + + result = (main != node); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _g_scan_token_node_enroll(GScanTokenNode *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + result = class->enroll(node, backend, maxsize, slow); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_enroll(GScanTokenNode *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + + assert(g_engine_backend_get_atom_max_size(backend) == maxsize); + + *slow = 0; + + result = _g_scan_token_node_enroll(node, backend, maxsize, slow); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_build_id(GScanTokenNode *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + if (class->build_id == NULL) + result = true; + else + result = class->build_id(node, backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void _g_scan_token_node_check_forward(const GScanTokenNode *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + if (node->flags & STNF_MAIN) + { + //assert(*skip); //REMME + *skip = false; + } + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + class->check_forward(node, params, cflags, skip); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_check_forward(const GScanTokenNode *node, scan_node_check_params_t *params) +{ + node_search_offset_t offset; /* Espace des correspondances */ + bool skip; /* Mise en attente des analyses*/ + size_t ocount; /* Quantité de bornes présentes*/ + node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */ + size_t pcount; /* Nombre de correspondances */ + match_area_t * const *pending_ptr; /* Correspondances actuelles */ + size_t p; /* Boucle de parcours #2 */ + match_area_t *pending; /* Correspondance à traiter */ + phys_t old_end; /* Ancien point d'arrivée */ + size_t o; /* Boucle de parcours #1 */ + const node_offset_range_t *range; /* Bornes d'espace à parcourir */ + phys_t new_end; /* Nouveau point d'arrivée */ + + init_node_search_offset(¶ms->offset); + + skip = true; + + _g_scan_token_node_check_forward(node, params, TNCF_UPDATE_IN_PLACE, &skip); + + +#if 0 // FIXME + + /** + * Si un décalage entre octets n'a pas été consommé, + * les résultats sont étendus à minima. + */ + + ranges_ptr = get_node_search_offset_ranges(&offset, &ocount); + + if (ocount > 0) + { + /** + * Dans le cas où un unique noeud ne renvoie que vers un espace (par + * exemple : "$a = { [0] }"), il n'y a pas de résultats, donc pas + * d'initialisation. + * + * La réinitialisation des décomptes va tiquer pour cet état. La + * phase d'extension des résultats inexistants est ainsi sautée. + */ + if (count_pending_matches(matches) == 0) + { + + + for (o = 0; o < ocount; o++) + { + range = (*ranges_ptr) + o; + + + printf("range: %u - %u\n", + (unsigned int)range->min, + (unsigned int)range->max); + + + /* + new_end = old_end + range->min; + + if (new_end > matches->content_end) + new_end = matches->content_end; + + add_pending_match(pending_matches_t *, phys_t, phys_t); + + extend_pending_match_ending(matches, p, new_end); + */ + + } + + + + + + + goto offset_done; + + } + + reset_pending_matches_ttl(matches); + + pending_ptr = get_all_pending_matches(matches, &pcount); + + for (p = 0; p < pcount; p++) + { + pending = (*pending_ptr) + p; + + old_end = pending->end; + + for (o = 0; o < ocount; o++) + { + range = (*ranges_ptr) + o; + + new_end = old_end + range->min; + + if (new_end > matches->content_end) + new_end = matches->content_end; + + extend_pending_match_ending(matches, p, new_end); + + } + + } + + /** + * Pas besoin de purge ici puisque tous les résultats ont été traités + * au moins une fois, sans condition. + */ + /* purge_pending_matches(matches); */ + + offset_done: + + disable_all_ranges_in_node_search_offset(&offset); + + } + + assert(offset.used == 0); + +#endif + + exit_node_search_offset(¶ms->offset); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void _g_scan_token_node_check_backward(const GScanTokenNode *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + class->check_backward(node, params, cflags, skip); + + if (node->flags & STNF_MAIN) + { + //assert(*skip); //REMME + *skip = false; + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_check_backward(const GScanTokenNode *node, scan_node_check_params_t *params) +{ + node_search_offset_t offset; /* Espace des correspondances */ + bool skip; /* Mise en attente des analyses*/ + size_t ocount; /* Quantité de bornes présentes*/ + node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */ + size_t pcount; /* Nombre de correspondances */ + match_area_t * const *pending_ptr; /* Correspondances actuelles */ + size_t p; /* Boucle de parcours #2 */ + match_area_t *pending; /* Correspondance à traiter */ + phys_t old_start; /* Ancien point d'arrivée */ + size_t o; /* Boucle de parcours #1 */ + const node_offset_range_t *range; /* Bornes d'espace à parcourir */ + phys_t new_start; /* Nouveau point d'arrivée */ + + init_node_search_offset(¶ms->offset); + + skip = true; + + _g_scan_token_node_check_backward(node, params, TNCF_UPDATE_IN_PLACE, &skip); + +#if 0 // FIXME + + /** + * Si un décalage entre octets n'a pas été consommé, + * les résultats sont étendus à minima. + */ + + ranges_ptr = get_node_search_offset_ranges(&offset, &ocount); + + if (ocount > 0) + { + reset_pending_matches_ttl(matches); + + pending_ptr = get_all_pending_matches(matches, &pcount); + + for (p = 0; p < pcount; p++) + { + pending = (*pending_ptr) + p; + + old_start = pending->start; + + for (o = 0; o < ocount; o++) + { + range = (*ranges_ptr) + o; + + if (old_start < range->min) + new_start = 0; + else + new_start = old_start - range->min; + + if (new_start < matches->content_start) + new_start = matches->content_start; + + extend_pending_match_beginning(matches, p, new_start); + + } + + } + + /** + * Pas besoin de purge ici puisque tous les résultats ont été traités + * au moins une fois, sans condition. + */ + /* purge_pending_matches(matches); */ + + disable_all_ranges_in_node_search_offset(&offset); + + } + + assert(offset.used == 0); + +#endif + + exit_node_search_offset(¶ms->offset); + +} diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h new file mode 100644 index 0000000..5b1a247 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/node.h @@ -0,0 +1,127 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.h - prototypes pour la décomposition d'un motif de recherche en atomes assemblés + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "offset.h" +#include "../backend.h" +#include "../../context.h" +#include "../../matches/bytes.h" +#include "../../../../glibext/umemslice.h" + + +#define G_TYPE_SCAN_TOKEN_NODE g_scan_token_node_get_type() +#define G_SCAN_TOKEN_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNode)) +#define G_IS_SCAN_TOKEN_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE)) +#define G_SCAN_TOKEN_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNodeClass)) +#define G_IS_SCAN_TOKEN_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE)) +#define G_SCAN_TOKEN_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNodeClass)) + + +/* Décomposition d'un motif de recherche en atomes (instance) */ +typedef struct _GScanTokenNode GScanTokenNode; + +/* Décomposition d'un motif de recherche en atomes (classe) */ +typedef struct _GScanTokenNodeClass GScanTokenNodeClass; + + +/* Propriétés particulières pour noeud d'analyse */ +typedef enum _ScanTokenNodeFlags +{ + STNF_NONE = (0 << 0), /* Absence de singularité */ + STNF_FIRST = (1 << 0), /* Premier noeud de traitement */ + STNF_LAST = (1 << 1), /* Dernier noeud de traitement */ + STNF_MAIN = (1 << 2), /* Point de départ d'analyse */ + +} ScanTokenNodeFlags; + + +/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */ +GType g_scan_token_node_get_type(void); + +/* Communique l'intérêt d'un noeud au sein d'une analyse. */ +float g_scan_token_node_compute_weight_for_scan(const GScanTokenNode *); + + + +/* Indique les propriétés particulières d'un noeud d'analyse. */ +ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *); + +/* Marque le noeud avec des propriétés particulières. */ +void g_scan_token_node_set_flags(GScanTokenNode *, ScanTokenNodeFlags); + +/* Détermine et prépare les éléments clefs d'une arborescence. */ +bool g_scan_token_node_setup_tree(GScanTokenNode *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +bool g_scan_token_node_enroll(GScanTokenNode *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +bool g_scan_token_node_build_id(GScanTokenNode *, GEngineBackend *); + +/* Accès direct aux éléments utiles aux contrôles */ +typedef struct _scan_node_check_params_t +{ + GScanContext *context; /* Contexte de scan en cours */ + GBinContent *content; /* Contenu binaire associé */ + GUMemSlice *allocator; /* Allocateur pour zones */ + + phys_t content_start; /* Point de début du contenu */ + phys_t content_end; /* Point de fin du contenu */ + + node_search_offset_t offset; /* Décalages à respecter */ + + bool initialized; /* Etat du suivi */ + + /* TNCF_UPDATE_IN_PLACE */ + + match_area_t *main_areas; /* Zones principales à analyser*/ + size_t main_count; /* Taille de cette liste */ + + /* TNCF_CREATE_NEW */ + + match_area_t *created_areas; /* Zones principales à analyser*/ + size_t created_count; /* Taille de cette liste */ + + /* TNCF_KEEP_DISCARDED */ + + match_area_t *kept_areas; /* Zones principales à analyser*/ + size_t kept_count; /* Taille de cette liste */ + +} scan_node_check_params_t; + +/* Transforme les correspondances locales en trouvailles. */ +void g_scan_token_node_check_forward(const GScanTokenNode *, scan_node_check_params_t *); + +/* Transforme les correspondances locales en trouvailles. */ +void g_scan_token_node_check_backward(const GScanTokenNode *, scan_node_check_params_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/Makefile.am b/src/analysis/scan/patterns/tokens/nodes/Makefile.am new file mode 100644 index 0000000..b5da1ee --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/Makefile.am @@ -0,0 +1,24 @@ + +noinst_LTLIBRARIES = libanalysisscanpatternstokensnodes.la + + +libanalysisscanpatternstokensnodes_la_SOURCES = \ + any-int.h \ + any.h any.c \ + choice-int.h \ + choice.h choice.c \ + masked-int.h \ + masked.h masked.c \ + not-int.h \ + not.h not.c \ + plain-int.h \ + plain.h plain.c \ + sequence-int.h \ + sequence.h sequence.c + +libanalysisscanpatternstokensnodes_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatternstokensnodes_la_SOURCES:%c=) diff --git a/src/analysis/scan/patterns/tokens/nodes/any-int.h b/src/analysis/scan/patterns/tokens/nodes/any-int.h new file mode 100644 index 0000000..dd2e2e7 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/any-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * any-int.h - prototypes internes pour une suite d'octets quelconques + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H + + +#include "any.h" + + +#include "../atom.h" +#include "../node-int.h" + + + +/* Espace constitué d'un ou plusieurs octets quelconques (instance) */ +struct _GScanTokenNodeAny +{ + GScanTokenNode parent; /* A laisser en premier */ + + phys_t min; /* Quantité minimale */ + phys_t max; /* Quantité maximale */ + bool has_max; /* Quantité définie ? */ + +}; + +/* Espace constitué d'un ou plusieurs octets quelconques (classe) */ +struct _GScanTokenNodeAnyClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un noeud pointant une série d'octets. */ +bool g_scan_token_node_any_create(GScanTokenNodeAny *, const phys_t *, const phys_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/any.c b/src/analysis/scan/patterns/tokens/nodes/any.c new file mode 100644 index 0000000..4334fff --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/any.c @@ -0,0 +1,765 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * any.c - suite d'octets quelconques + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "any.h" + + +#include <assert.h> + + +#include "any-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des séries d'octets quelconques. */ +static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *); + +/* Initialise une instance de série d'octets quelconques. */ +static void g_scan_token_node_any_init(GScanTokenNodeAny *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_any_dispose(GScanTokenNodeAny *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_any_finalize(GScanTokenNodeAny *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *, GEngineBackend *, size_t, size_t *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une série d'octets quelconque, vide ou non. */ +G_DEFINE_TYPE(GScanTokenNodeAny, g_scan_token_node_any, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des séries d'octets quelconques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_any_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_any_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->apply = (apply_scan_token_node_flags_fc)NULL; + node->visit = (visit_scan_token_node_fc)NULL; + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_any_enroll; + node->check_forward = (check_scan_token_node_fc)g_scan_token_node_any_check_forward; + node->check_backward = (check_scan_token_node_fc)g_scan_token_node_any_check_backward; + +} + + +/****************************************************************************** +* * +* Paramètres : any = instance à initialiser. * +* * +* Description : Initialise une instance de série d'octets quelconques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_any_init(GScanTokenNodeAny *any) +{ + any->min = 0; + any->has_max = false; + +} + + +/****************************************************************************** +* * +* Paramètres : any = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_any_dispose(GScanTokenNodeAny *any) +{ + G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->dispose(G_OBJECT(any)); + +} + + +/****************************************************************************** +* * +* Paramètres : any = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_any_finalize(GScanTokenNodeAny *any) +{ + G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->finalize(G_OBJECT(any)); + +} + + +/****************************************************************************** +* * +* Paramètres : min = éventuelle quantité minimale à retrouver. * +* max = éventuelle quantité maximale à retrouver. * +* * +* Description : Construit un noeud pointant une série d'octets quelconques. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_any_new(const phys_t *min, const phys_t *max) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_ANY, NULL); + + if (!g_scan_token_node_any_create(G_SCAN_TOKEN_NODE_ANY(result), min, max)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : any = séquence d'octets quelconques à initialiser pleinement.* +* min = éventuelle quantité minimale à retrouver. * +* max = éventuelle quantité maximale à retrouver. * +* * +* Description : Met en place un noeud pointant une série d'octets. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_any_create(GScanTokenNodeAny *any, const phys_t *min, const phys_t *max) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (min != NULL) + any->min = *min; + else + any->min = 0; + + if (max != NULL) + { + any->max = *max; + + result = (any->min <= any->max); + + if (result && any->min == any->max) + result = (any->min > 0); + + } + + any->has_max = (max != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : any = séquence d'octets quelconques à étendre. * +* extra = étendue supplémentaire à intégrer. * +* * +* Description : Etend un noeud pointant une série d'octets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_any_merge(GScanTokenNodeAny *any, GScanTokenNodeAny *extra) +{ + any->min += extra->min; + + if (any->has_max && extra->has_max) + any->max += extra->max; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + bool forced; /* Inclusion dans un scan ? */ + + result = true; + + forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); + + if (forced) + *slow += (maxsize * 4); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + ScanTokenNodeFlags flags; /* Particularités du noeud */ + bool forced; /* Inclusion dans un scan ? */ + phys_t size; /* Quantité d'octets considérés*/ + phys_t match_size; /* Taille de correspondance */ + phys_t i; /* Boucle de parcours #1 */ + match_area_t *space; /* Nouvelle zone à intégrer */ + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t after; /* Espace disposible après */ + phys_t min_end; /* Fin la plus proche possible */ + phys_t max_end; /* Fin la plus éloignée trouvée*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #2 */ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)); + + forced = (flags & STNF_MAIN); + + assert((!params->initialized && forced) || (params->initialized & !forced)); + + /** + * La situation forcée correspond au cas particulier d'une définition + * complètement abstraite : ??, ?? ??, etc. + */ + if (forced) + { + size = params->content_end - params->content_start; + + if (node->has_max && 0 /* greedy ? */) + { + match_size = node->max; + + if (match_size > size) + match_size = node->min; + + } + else + match_size = node->min; + + /** + * Si le contenu binaire est trop petit pour contenir au moins un enregistrement, + * aucune correspondance n'est enregistrée. Comme le noeud est le principale, ie. + * seul et unique, l'analyse s'arrête ensuite d'elle même. + * + * Si le contenu binaire est suffisamment large, des espaces sont créés et l'analyse + * se termine ensuite. La conservation des espaces n'est donc pas utile, ni réalisée. + */ + + if (match_size <= size) + { + size -= (match_size - 1); + + assert(cflags & TNCF_UPDATE_IN_PLACE); + + for (i = 0; i < size; i++) + { + space = g_umem_slice_alloc(params->allocator); + + space->start = params->content_start + i; + space->end = space->start + match_size; + + add_tail_match_area(space, ¶ms->main_areas); + + } + + params->main_count += size; + + } + + } + + /** + * Situation usuelle : des espaces séparent deux noeuds. + */ + else + { + assert(params->initialized); + + /** + * Les espaces existants sont à compléter. La présence de tels espaces + * restant à traiter peut provenir d'un aiguillage imposé par un motif + * tel que : + * + * ( aa ?? ?? | bb cc dd ) [0-5] ee ee + * + * Deux espaces sont à considérer avant de rechercher des octets ee : + * [2-7] et [0-5]. + * + * Note : ces espaces peuvent être disjoints. + * + * Si aucun espace n'est en place, un est créé. + */ + + extend_node_search_offset(¶ms->offset, node->min, node->max, node->has_max); + + /** + * Si un décalage enregistré ne peut être consommé par un noeud, les + * résultats sont étendus ici à minima ou maxima. + */ + + if (flags & STNF_LAST) + { + assert(offsets_exist(¶ms->offset)); + + if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(area->end <= params->content_end); + + after = params->content_end - area->end; + + if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + min_end = params->content_end; + max_end = params->content_start; + + updated = false; + + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + + for (r = 0; r < rcount; r++) + { + if (ranges[r].min > after) + continue; + + updated_edge = area->end + ranges[r].min; + + if (updated_edge < min_end) + min_end = updated_edge; + + if (ranges[r].has_max) + { + if (ranges[r].max > after) + updated_edge = params->content_end; + else + updated_edge = area->end + ranges[r].max; + + if (updated_edge > max_end) + max_end = updated_edge; + + } + + updated = true; + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->end = (1 /* greedy */ ? min_end : max_end); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + disable_all_ranges_in_node_search_offset(¶ms->offset); + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + ScanTokenNodeFlags flags; /* Particularités du noeud */ +#ifndef NDEBUG + bool forced; /* Inclusion dans un scan ? */ +#endif + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t before; /* Espace disposible avant */ + phys_t min_start; /* Début le plus proche trouvé */ + phys_t max_start; /* Début le plus distant trouvé*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours */ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + /** + * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors + * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu. + */ + + assert(params->initialized); + + flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)); + + /** + * Si les recherches associées au noeud ont été forcées, alors les traitements + * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté. + */ +#ifndef NDEBUG + forced = (flags & STNF_MAIN); + assert(!forced); +#endif + + /** + * Les considérations pour l'extension des espaces en place sont identiques + * à celles formulées dans la fonction g_scan_token_node_any_check_forward(). + */ + + extend_node_search_offset(¶ms->offset, node->min, node->max, node->has_max); + + /** + * Si un décalage enregistré ne peut être consommé par un noeud, les + * résultats sont étendus ici à minima ou maxima. + */ + + if (flags & STNF_FIRST) + { + assert(offsets_exist(¶ms->offset)); + + if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(params->content_start <= area->start); + + before = area->start - params->content_start; + + if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + min_start = params->content_start; + max_start = params->content_end; + + updated = false; + + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + + for (r = 0; r < rcount; r++) + { + if (ranges[r].min > before) + continue; + + updated_edge = area->start - ranges[r].min; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (ranges[r].has_max) + { + if (ranges[r].max > before) + updated_edge = params->content_start; + else + updated_edge = area->start - ranges[r].max; + + if (updated_edge < max_start) + max_start = updated_edge; + + } + + updated = true; + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->start = (1 /* greedy */ ? min_start : max_start); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + disable_all_ranges_in_node_search_offset(¶ms->offset); + + } + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/any.h b/src/analysis/scan/patterns/tokens/nodes/any.h new file mode 100644 index 0000000..9b2233f --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/any.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * any.h - prototypes pour une suite d'octets quelconques + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H + + +#include <glib-object.h> + + +#include "../node.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_ANY g_scan_token_node_any_get_type() +#define G_SCAN_TOKEN_NODE_ANY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAny)) +#define G_IS_SCAN_TOKEN_NODE_ANY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_ANY)) +#define G_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass)) +#define G_IS_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_ANY)) +#define G_SCAN_TOKEN_NODE_ANY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass)) + + +/* Espace constitué d'un ou plusieurs octets quelconques (instance) */ +typedef struct _GScanTokenNodeAny GScanTokenNodeAny; + +/* Espace constitué d'un ou plusieurs octets quelconques (classe) */ +typedef struct _GScanTokenNodeAnyClass GScanTokenNodeAnyClass; + + +/* Indique le type défini pour une série d'octets quelconque, vide ou non. */ +GType g_scan_token_node_any_get_type(void); + +/* Construit un noeud pointant une série d'octets quelconques. */ +GScanTokenNode *g_scan_token_node_any_new(const phys_t *, const phys_t *); + +/* Etend un noeud pointant une série d'octets. */ +void g_scan_token_node_any_merge(GScanTokenNodeAny *, GScanTokenNodeAny *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/choice-int.h b/src/analysis/scan/patterns/tokens/nodes/choice-int.h new file mode 100644 index 0000000..77a4058 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/choice-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * choice-int.h - prototypes internes pour des décompositions alternatives de motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H + + +#include "choice.h" + + +#include "../node-int.h" + + + +/* Décompositions alternatives de motif de recherche (instance) */ +struct _GScanTokenNodeChoice +{ + GScanTokenNode parent; /* A laisser en premier */ + + GScanTokenNode **children; /* Sous-noeuds à représenter */ + size_t count; /* Taille de cette liste */ + +}; + +/* Décompositions alternatives de motif de recherche (classe) */ +struct _GScanTokenNodeChoiceClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c new file mode 100644 index 0000000..2a5e5f5 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/choice.c @@ -0,0 +1,646 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * choice.c - décompositions alternatives de motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "choice.h" + + +#include <assert.h> + + +#include "choice-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des décompositions alternatives. */ +static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *); + +/* Initialise une instance de décompositions alternatives. */ +static void g_scan_token_node_choice_init(GScanTokenNodeChoice *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Communique l'intérêt d'un noeud au sein d'une analyse. */ +static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *); + +/* Prend acte d'une nouvelle propriété pour le noeud. */ +static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTokenNodeFlags); + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *, GEngineBackend *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour des décompositions alternatives de motif de recherche. */ +G_DEFINE_TYPE(GScanTokenNodeChoice, g_scan_token_node_choice, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des décompositions alternatives. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_choice_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_choice_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_choice_compute_weight_for_scan; + node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_choice_apply_flags; + node->visit = (visit_scan_token_node_fc)g_scan_token_node_choice_visit; + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_choice_enroll; + node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_choice_build_id; + node->check_forward = (check_scan_token_node_fc)g_scan_token_node_choice_check_forward; + node->check_backward = (check_scan_token_node_fc)g_scan_token_node_choice_check_backward; + +} + + +/****************************************************************************** +* * +* Paramètres : choice = instance à initialiser. * +* * +* Description : Initialise une instance de décompositions alternatives. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_init(GScanTokenNodeChoice *choice) +{ + choice->children = NULL; + choice->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : choice = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *choice) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < choice->count; i++) + g_clear_object(&choice->children[i]); + + G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->dispose(G_OBJECT(choice)); + +} + + +/****************************************************************************** +* * +* Paramètres : choice = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *choice) +{ + if (choice->children != NULL) + free(choice->children); + + G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->finalize(G_OBJECT(choice)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit une série de décompositions alternatives de motif. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_choice_new(void) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_CHOICE, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : choice = ensemble de noeuds à compléter. * +* node = nouveau noeud à intégrer. * +* * +* Description : Ajoute un noeud à aux décompositions alternatives de motif. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_choice_add(GScanTokenNodeChoice *choice, GScanTokenNode *node) +{ + choice->children = realloc(choice->children, ++choice->count * sizeof(GScanTokenNode *)); + + choice->children[choice->count - 1] = node; + g_object_ref(G_OBJECT(node)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à consulter. * +* * +* Description : Communique l'intérêt d'un noeud au sein d'une analyse. * +* * +* Retour : Poids de l'importance pour un départ de scan. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *node) +{ + float result; /* Valeur à retourner */ + size_t weight_count; /* Nombre de comptabilisations */ + size_t i; /* Boucle de parcours */ + float weight; /* Nouveau poids à intégrer */ + + result = 0; + + weight_count = 0; + + for (i = 0; i < node->count; i++) + { + weight = g_scan_token_node_compute_weight_for_scan(node->children[i]); + + if (weight > 0) + { + result += weight; + weight_count++; + } + + } + + if (weight_count != node->count) + result = 0; + else + result /= weight_count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à mettre à jour. * +* flags = propriétés particulières à associer au noeud. * +* * +* Description : Prend acte d'une nouvelle propriété pour le noeud. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *node, ScanTokenNodeFlags flags) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < node->count; i++) + g_scan_token_node_set_flags(node->children[i], flags); + +} + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à effectuer. * +* points = points capitaux de l'arborescence. [OUT] * +* * +* Description : Parcourt une arborescence de noeuds et y relève des éléments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree_points_t *points) +{ + size_t first_plain_count; /* Décompte de noeuds textuels */ + size_t i; /* Boucle de parcours */ + scan_tree_points_t tmp_points; /* Synthèse d'analyse locale */ + + if (points->first_plain != NULL) + return; + + first_plain_count = 0; + + for (i = 0; i < node->count; i++) + { + tmp_points.first_plain = NULL; + tmp_points.best_masked = NULL; + + g_scan_token_node_visit(node->children[i], &tmp_points); + + if (tmp_points.first_plain != NULL) + first_plain_count++; + + } + + if (first_plain_count == node->count) + points->first_plain = G_SCAN_TOKEN_NODE(node); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < node->count && result; i++) + result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + + result = true; + + for (i = 0; i < node->count && result; i++) + result = g_scan_token_node_build_id(node->children[i], backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + bool initialized; /* Initialisation du suivi ? */ + match_area_t *collected_areas; /* Zones mises en place ici */ + size_t collected_count; /* Quantité de ces zones */ + TokenNodeCheckFlags local_cflags; /* Particularités nouvelles */ + size_t i; /* Boucle de parcours */ + scan_node_check_params_t local_params; /* Rassemblement de paramètres */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + /* Lancement des sous-traitements */ + + initialized = false; + + collected_areas = NULL; + collected_count = 0; + + local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW; + + for (i = 0; i < node->count; i++) + { + local_params = *params; + + local_params.created_areas = NULL; + local_params.created_count = 0; + + local_params.kept_areas = NULL; + local_params.kept_count = 0; + + if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count) + local_cflags = cflags; + + _g_scan_token_node_check_forward(node->children[i], &local_params, local_cflags, skip); + + initialized |= local_params.initialized; + + if (local_cflags & TNCF_KEEP_DISCARDED) + { + merge_match_areas(&collected_areas, &local_params.kept_areas); + collected_count += local_params.kept_count; + } + + else if (local_cflags & TNCF_CREATE_NEW) + { + merge_match_areas(&collected_areas, &local_params.created_areas); + collected_count += local_params.created_count; + } + + else + { + assert(local_cflags & TNCF_UPDATE_IN_PLACE); + + merge_match_areas(&collected_areas, &local_params.main_areas); + collected_count += local_params.main_count; + + } + + } + + /* Enregistrement des résultats finaux */ + + if (collected_count > 1) + sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL); + + if (0x0) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count); + + params->initialized = initialized; + + if (cflags & TNCF_KEEP_DISCARDED) + { + params->kept_areas = collected_areas; + params->kept_count = collected_count; + } + + else if (cflags & TNCF_CREATE_NEW) + { + params->created_areas = collected_areas; + params->created_count = collected_count; + } + + else + { + assert(cflags & TNCF_UPDATE_IN_PLACE); + + params->main_areas = collected_areas; + params->main_count = collected_count; + + } + + + + + + /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python) + + + + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + match_area_t *collected_areas; /* Zones mises en place ici */ + size_t collected_count; /* Quantité de ces zones */ + TokenNodeCheckFlags local_cflags; /* Particularités nouvelles */ + size_t i; /* Boucle de parcours */ + scan_node_check_params_t local_params; /* Rassemblement de paramètres */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + /** + * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors + * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu. + */ + + assert(params->initialized); + + /* Lancement des sous-traitements */ + + collected_areas = NULL; + collected_count = 0; + + local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW; + + for (i = 0; i < node->count; i++) + { + local_params = *params; + + local_params.created_areas = NULL; + local_params.created_count = 0; + + local_params.kept_areas = NULL; + local_params.kept_count = 0; + + if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count) + local_cflags = cflags; + + _g_scan_token_node_check_backward(node->children[i], &local_params, local_cflags, skip); + + if (local_cflags & TNCF_KEEP_DISCARDED) + { + merge_match_areas(&collected_areas, &local_params.kept_areas); + collected_count += local_params.kept_count; + } + + else if (local_cflags & TNCF_CREATE_NEW) + { + merge_match_areas(&collected_areas, &local_params.created_areas); + collected_count += local_params.created_count; + } + + else + { + assert(local_cflags & TNCF_UPDATE_IN_PLACE); + + merge_match_areas(&collected_areas, &local_params.main_areas); + collected_count += local_params.main_count; + + } + + } + + /* Enregistrement des résultats finaux */ + + if (collected_count > 1) + sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL); + + if (0x0) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count); + + if (cflags & TNCF_KEEP_DISCARDED) + { + params->kept_areas = collected_areas; + params->kept_count = collected_count; + } + + else if (cflags & TNCF_CREATE_NEW) + { + params->created_areas = collected_areas; + params->created_count = collected_count; + } + + else + { + assert(cflags & TNCF_UPDATE_IN_PLACE); + + params->main_areas = collected_areas; + params->main_count = collected_count; + + } + + + + + + /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python) + + + + + + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.h b/src/analysis/scan/patterns/tokens/nodes/choice.h new file mode 100644 index 0000000..e793b1e --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/choice.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * choice.h - prototypes pour des décompositions alternatives de motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H + + +#include <glib-object.h> + + +#include "../node.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_CHOICE g_scan_token_node_choice_get_type() +#define G_SCAN_TOKEN_NODE_CHOICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoice)) +#define G_IS_SCAN_TOKEN_NODE_CHOICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE)) +#define G_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass)) +#define G_IS_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE)) +#define G_SCAN_TOKEN_NODE_CHOICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass)) + + +/* Décompositions alternatives de motif de recherche (instance) */ +typedef struct _GScanTokenNodeChoice GScanTokenNodeChoice; + +/* Décompositions alternatives de motif de recherche (classe) */ +typedef struct _GScanTokenNodeChoiceClass GScanTokenNodeChoiceClass; + + +/* Indique le type défini pour des décompositions alternatives de motif de recherche. */ +GType g_scan_token_node_choice_get_type(void); + +/* Construit une série de décompositions alternatives de motif. */ +GScanTokenNode *g_scan_token_node_choice_new(void); + +/* Ajoute un noeud à aux décompositions alternatives de motif. */ +void g_scan_token_node_choice_add(GScanTokenNodeChoice *, GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/masked-int.h b/src/analysis/scan/patterns/tokens/nodes/masked-int.h new file mode 100644 index 0000000..5fcc330 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * masked-int.h - prototypes internes pour la gestion d'une recherche de motif partielle + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H + + +#include "masked.h" + + +#include "../node-int.h" + + + +/* Bribe de motif partielle pour recherches (instance) */ +struct _GScanTokenNodeMasked +{ + GScanTokenNode parent; /* A laisser en premier */ + + masked_byte_t *bytes; /* Série d'octets masqués */ + size_t len; /* Taille de cette série */ + + sized_binary_t *raw; /* Liste de motifs à couvrir */ + size_t raw_count; /* Taille de cette liste */ + + tracked_scan_atom_t *enrolled_atoms; /* Atomes correspondants */ + size_t enrolled_count; /* Quantité avec identifiant */ + +}; + +/* Bribe de motif partielle pour recherches (classe) */ +struct _GScanTokenNodeMaskedClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une bribe de motif partielle. */ +bool g_scan_token_node_masked_create(GScanTokenNodeMasked *, const masked_byte_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.c b/src/analysis/scan/patterns/tokens/nodes/masked.c new file mode 100644 index 0000000..5194cb8 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/masked.c @@ -0,0 +1,1135 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * masked.c - gestion d'une recherche de motif partielle + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "masked.h" + + +#include <assert.h> + + +#include "masked-int.h" +#include "../../backends/bitap.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des bribes de motif partielles. */ +static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *); + +/* Initialise une instance de bribe de motif partielle. */ +static void g_scan_token_node_masked_init(GScanTokenNodeMasked *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *, GEngineBackend *); + +/* Détermine si un contenu d'intérêt est présent à une position. */ +static bool check_scan_token_node_masked_content(const masked_byte_t *, size_t, phys_t, GBinContent *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */ +G_DEFINE_TYPE(GScanTokenNodeMasked, g_scan_token_node_masked, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des bribes de motif partielles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_masked_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_masked_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->apply = (apply_scan_token_node_flags_fc)NULL; + node->visit = (visit_scan_token_node_fc)g_scan_token_node_masked_visit; + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_masked_enroll; + node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_masked_build_id; + node->check_forward = (check_scan_token_node_fc)g_scan_token_node_masked_check_forward; + node->check_backward = (check_scan_token_node_fc)g_scan_token_node_masked_check_backward; + +} + + +/****************************************************************************** +* * +* Paramètres : masked = instance à initialiser. * +* * +* Description : Initialise une instance de bribe de motif partielle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_init(GScanTokenNodeMasked *masked) +{ + masked->bytes = NULL; + masked->len = 0; + + masked->raw = NULL; + masked->raw_count = 0; + + masked->enrolled_atoms = NULL; + masked->enrolled_count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : masked = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *masked) +{ + G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->dispose(G_OBJECT(masked)); + +} + + +/****************************************************************************** +* * +* Paramètres : masked = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *masked) +{ + size_t i; /* Boucle de parcours */ + + if (masked->bytes != NULL) + free(masked->bytes); + + for (i = 0; i < masked->raw_count; i++) + exit_szstr(&masked->raw[i]); + + if (masked->raw != NULL) + free(masked->raw); + + if (masked->enrolled_atoms != NULL) + free(masked->enrolled_atoms); + + G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->finalize(G_OBJECT(masked)); + +} + + +/****************************************************************************** +* * +* Paramètres : byte = valeur masquée à intégrer. * +* * +* Description : Construit une bribe de motif partielle. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *byte) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_MASKED, NULL); + + if (!g_scan_token_node_masked_create(G_SCAN_TOKEN_NODE_MASKED(result), byte)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : masked = bribe partielle à initialiser pleinement. * +* byte = valeur masquée à intégrer. * +* * +* Description : Met en place une bribe de motif partielle. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_masked_create(GScanTokenNodeMasked *masked, const masked_byte_t *byte) +{ + bool result; /* Bilan à retourner */ + + result = true; + + g_scan_token_node_masked_add(masked, byte); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : masked = ensemble de noeuds à compléter. * +* byte = valeur masquée à intégrer. * +* * +* Description : Enregistre la valeur d'octet à rechercher avec son masque. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_masked_add(GScanTokenNodeMasked *masked, const masked_byte_t *byte) +{ + assert((byte->value & 0x0f) == 0 || (byte->value & 0xf0) == 0); + + masked->bytes = realloc(masked->bytes, ++masked->len * sizeof(masked_byte_t)); + + masked->bytes[masked->len - 1] = *byte; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à effectuer. * +* points = points capitaux de l'arborescence. [OUT] * +* * +* Description : Parcourt une arborescence de noeuds et y relève des éléments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree_points_t *points) +{ + GScanTokenNodeMasked *other; /* Concurrence à mesurer */ + + if (points->best_masked == NULL) + points->best_masked = G_SCAN_TOKEN_NODE(node); + + else + { + other = G_SCAN_TOKEN_NODE_MASKED(points->best_masked); + + if (node->len > other->len) + points->best_masked = G_SCAN_TOKEN_NODE(node); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + bool forced; /* Inclusion dans un scan ? */ + //size_t len_to_enroll; /* Taille à considérer */ + size_t i; /* Boucle de parcours */ + + result = true; + + forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); + + if (forced) + { + *slow += (maxsize * 2); + + node->raw = make_atoms_from_masked_bytes(node->bytes, node->len, &node->raw_count); + + /** + * Dans le cas bien précis de l'usage de l'algorithme Bitap pour les recherches + * dans le contenu binaire à analyser, on tire parti du coût nul des recherches + * multiples pour une même position. + */ + + if (G_IS_BITAP_BACKEND(backend)) + { + //len_to_enroll = (node->len < maxsize ? node->len : maxsize); + + /* TODO */ + assert(false); + + + node->enrolled_count = 1; + + } + + else + { + node->enrolled_atoms = malloc(node->raw_count * sizeof(tracked_scan_atom_t)); + node->enrolled_count = node->raw_count; + + for (i = 0; i < node->enrolled_count && result; i++) + { + find_best_atom(&node->raw[i], maxsize, &node->enrolled_atoms[i], NULL); + + /** + * Correction : si l'atome ne représente qu'une vue partielle, + * la validation rapide ne peut s'appliquer. + */ + if (node->enrolled_atoms[i].fast_check) + node->enrolled_atoms[i].fast_check = (node->enrolled_atoms[i].len == node->len); + + result = enroll_prepared_atom(&node->raw[i], backend, &node->enrolled_atoms[i]); + + } + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + + result = true; + + for (i = 0; i < node->enrolled_count && result; i++) + result = build_atom_pattern_id(&node->enrolled_atoms[i], backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = octets partiels avec leur masque à interpréter. * +* len = quantité d'octets à interpréter. * +* start = point d'analyse à respecter. * +* content = accès au contenu brut pour vérifications (optim.) * +* * +* Description : Détermine si un contenu d'intérêt est présent à une position.* +* * +* Retour : Bilan de l'analyse : true pour une correspondance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, size_t len, phys_t start, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + vmpa2t pos; /* Position dans les données */ + const bin_t *ptr; /* Accès aux données brutes */ + size_t i; /* Boucle de parcours */ + + result = false; + + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); + + ptr = g_binary_content_get_raw_access(content, &pos, len); + + for (i = 0; i < len; i++) + { + if ((ptr[i] & bytes[i].mask) != bytes[i].value) + break; + } + + result = (i == len); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ +#ifndef NDEBUG + bool forced; /* Inclusion dans un scan ? */ +#endif + match_area_t **areas; /* Liste de zones à constituer */ + size_t *count; /* Taille de cette liste */ + bool copy; /* Besoin d'une copie ? */ + bool inverted; /* Inversion des bilans ? */ + size_t i; /* Boucle de parcours #1 */ + const tracked_scan_atom_t *atom; /* Atome correspondant */ + match_area_t *atoms; /* Localisations des bribes */ + bool first_round; /* Premier tour de traitement */ + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t start; /* Début potentiel de motif */ + bool status; /* Bilan d'une correspondance */ + phys_t after; /* Espace disposible après */ + phys_t min_end; /* Fin la plus proche possible */ + phys_t max_end; /* Fin la plus éloignée trouvée*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + /** + * Si l'analyse arrive à un ou plusieurs octets masqués, soit il s'agit du + * premier noeud, et la génération d'atomes a été forcée pour obtenir des + * points de départ, soit des correspondances ont été établies au préalable, + * et il ne doit alors pas y avoir d'atome mis en place (si l'initialisation + * ne provient pas d'une mise en place artificielle par une inversion NOT). + */ +#ifndef NDEBUG + forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); + assert((!params->initialized && forced) || (params->initialized && (!forced || cflags & TNCF_KEEP_DISCARDED))); +#endif + + if (!params->initialized) + { + /* Destinations établies une fois pour toutes */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + areas = ¶ms->kept_areas; + count = ¶ms->kept_count; + + copy = false; + inverted = true; + + } + + else if (cflags & TNCF_CREATE_NEW) + { + areas = ¶ms->created_areas; + count = ¶ms->created_count; + + copy = true; + inverted = false; + + } + + else + { + assert(cflags & TNCF_UPDATE_IN_PLACE); + + areas = ¶ms->main_areas; + count = ¶ms->main_count; + + copy = false; + inverted = false; + + } + + /* Parcours des combinaisons enregistrées */ + + for (i = 0; i < node->enrolled_count; i++) + { + atom = &node->enrolled_atoms[i]; + + atoms = g_scan_context_get_atom_matches(params->context, atom->pid); + + first_round = (*count == 0); + + if (atom->fast_check) + { + /** + * Toutes les correspondances sont validées d'office car le motif identifié + * correspondant au motif complet. + */ + + if (!inverted) + { + for_each_match_area(area, atoms) + { + /** + * La modification de la zone d'origine est possible dans tous les cas + * car cette zone a été allouée de façon dédiée à un type de correspondances + * et ne sera pas réutilisée comme autre source de correspondance ailleurs. + */ + + assert(area->end >= atom->len); + + area->start = area->end - atom->len; + + (*count)++; + + } + + } + + else + atoms = NULL; + + } + + else + { + for_each_match_area_safe(area, &atoms, next) + { + start = area->end - atom->len - atom->pos; + + status = check_scan_token_node_masked_content(node->bytes, node->len, + start, params->content); + + if (status) + { + /** + * La modification de la zone d'origine est possible dans tous les cas + * car cette zone a été allouée de façon dédiée à un type de correspondances + * et ne sera pas réutilisée comme autre source de correspondance ailleurs. + */ + + if (!inverted) + { + area->start = start; + area->end += atom->rem; + + (*count)++; + + } + else + del_match_area(area, &atoms); + + } + + else + { + /** + * Les principes de modifications restent valables, même inversés. + */ + if (inverted) + { + area->start = start; + area->end += atom->rem; + + (*count)++; + + } + else + del_match_area(area, &atoms); + + } + + } + + + } + + /* Mise à jour de la liste */ + + if (atoms != NULL) + { + if (first_round) + *areas = atoms; + + else + merge_match_areas(areas, &atoms); + + } + + } + + } + + /** + * Poursuite des traitements sur des correspondances déjà amorcées, impliquant + * des comparaisons entières de motifs. + */ + else + { + if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(area->end <= params->content_end); + + after = params->content_end - area->end; + + if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + /** + * S'il s'avère qu'il existe de multiples correspondances dans l'espace + * analysé, c'est la prise en compte d'une éventuelle avarice quant aux + * distances consommées qui va sélectionner la position d'une bribe de + * correspondance retenue. + * + * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2' peuvent être + * valides pour un même contenu : + * + * aa.bbb -> correspondance 'aa.bb' + * ^ + * + * aa.bbb -> correspondance 'aa..bb' + * ^ + */ + + min_end = params->content_end; + max_end = params->content_start; + + updated = false; + + /* Souplesse dans les positions ? */ + if (offsets_exist(¶ms->offset)) + { + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + + for (r = 0; r < rcount; r++) + { + assert(ranges[r].has_max); + assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK); + + for (p = ranges[r].min; p <= ranges[r].max; p++) + { + /** + * Si la fin d'une correspondance potentielle est trop près de + * la fin du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if ((p + node->len) > after) + break; + + status = check_scan_token_node_masked_content(node->bytes, node->len, + area->end + p, params->content); + + if (status) + { + updated_edge = area->end + p + node->len; + + if (updated_edge < min_end) + min_end = updated_edge; + + if (updated_edge > max_end) + max_end = updated_edge; + + updated = true; + + } + + } + + } + + } + + /* Position immédiatement attendue */ + else + { + /** + * Si la fin d'une correspondance potentielle est trop près de + * la fin du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if (node->len <= after) + { + status = check_scan_token_node_masked_content(node->bytes, node->len, + area->end, params->content); + + if (status) + { + updated_edge = area->end + node->len; + + min_end = updated_edge; + max_end = updated_edge; + + updated = true; + + } + + } + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->end = (1 /* greedy */ ? min_end : max_end); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + } + + params->initialized = true; + + disable_all_ranges_in_node_search_offset(¶ms->offset); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ +#ifndef NDEBUG + bool forced; /* Inclusion dans un scan ? */ +#endif + + + + bool status; /* Bilan d'une correspondance */ + + + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t before; /* Espace disposible avant */ + phys_t min_start; /* Début le plus proche trouvé */ + phys_t max_start; /* Début le plus distant trouvé*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + /** + * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors + * du sens de lecteur normal). Donc l'initialisation a déjà dû avoir lieu. + */ + assert(params->initialized); + + /** + * Si les recherches associées au noeud ont été forcées, alors les traitements + * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté. + */ +#ifndef NDEBUG + forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); + assert(!forced); +#endif + + + + + /** + * ............. + */ + if (0) + { + + + ; + + + + } + + /** + * Poursuite des traitements sur des correspondances déjà amorcées, impliquant + * des comparaisons entières de motifs. + */ + else + { + if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(params->content_start <= area->start); + + before = area->start - params->content_start; + + if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + /** + * Il ne peut y avoir qu'une seule séquence d'octets à un même + * emplacement. En revanche, des modificateurs peuvent construire + * possédant une même base, mais offrant des suffixes différents + * (par exemple, un marqueur nul UTF-16 final en complément). + * + * L'ensemble des combinaisons produites doit ainsi être exploré. + */ + + min_start = params->content_start; + max_start = params->content_end; + + updated = false; + + /* Souplesse dans les positions ? */ + if (offsets_exist(¶ms->offset)) + { + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + + for (r = 0; r < rcount; r++) + { + assert(ranges[r].has_max); + assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK); + + for (p = ranges[r].min; p <= ranges[r].max; p++) + { + /** + * Si la fin d'une correspondance potentielle est trop près de + * la fin du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if ((p + node->len) > before) + break; + + status = check_scan_token_node_masked_content(node->bytes, node->len, + area->start - node->len - p, + params->content); + + if (status) + { + updated_edge = area->start - node->len - p; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (updated_edge < max_start) + max_start = updated_edge; + + updated = true; + + } + + } + + } + + } + + /* Position immédiatement attendue */ + else + { + /** + * Si la fin d'une correspondance potentielle est trop près du + * début du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if (node->len <= before) + { + status = check_scan_token_node_masked_content(node->bytes, node->len, + area->start - node->len, + params->content); + + if (status) + { + updated_edge = area->start - node->len; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (updated_edge < max_start) + max_start = updated_edge; + + updated = true; + + } + + } + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->start = (1 /* greedy */ ? min_start : max_start); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + } + + disable_all_ranges_in_node_search_offset(¶ms->offset); + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.h b/src/analysis/scan/patterns/tokens/nodes/masked.h new file mode 100644 index 0000000..04a05bc --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/masked.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * masked.h - prototypes pour la gestion d'une recherche de motif partielle + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H + + +#include <glib-object.h> + + +#include "../atom.h" +#include "../node.h" +#include "../../../../../arch/archbase.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_MASKED g_scan_token_node_masked_get_type() +#define G_SCAN_TOKEN_NODE_MASKED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMasked)) +#define G_IS_SCAN_TOKEN_NODE_MASKED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED)) +#define G_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass)) +#define G_IS_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED)) +#define G_SCAN_TOKEN_NODE_MASKED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass)) + + +/* Bribe de motif partielle pour recherches (instance) */ +typedef struct _GScanTokenNodeMasked GScanTokenNodeMasked; + +/* Bribe de motif partielle pour recherches (classe) */ +typedef struct _GScanTokenNodeMaskedClass GScanTokenNodeMaskedClass; + + +/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */ +GType g_scan_token_node_masked_get_type(void); + +/* Construit une bribe de motif partielle. */ +GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *); + +/* Enregistre la valeur d'octet à rechercher avec son masque. */ +void g_scan_token_node_masked_add(GScanTokenNodeMasked *, const masked_byte_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/not-int.h b/src/analysis/scan/patterns/tokens/nodes/not-int.h new file mode 100644 index 0000000..5f92afd --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/not-int.h @@ -0,0 +1,57 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * not-int.h - prototypes internes pour l'inversion de résultats de correspondances établis + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H + + +#include "not.h" + + +#include "../node-int.h" + + + +/* Inversion de résultats de correspondances établis (instance) */ +struct _GScanTokenNodeNot +{ + GScanTokenNode parent; /* A laisser en premier */ + + GScanTokenNode *child; /* Sous-noeud à considérer */ + +}; + +/* Inversion de résultats de correspondances établis (classe) */ +struct _GScanTokenNodeNotClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une inversion de résultats de correspondances. */ +bool g_scan_token_node_not_create(GScanTokenNodeNot *, GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/not.c b/src/analysis/scan/patterns/tokens/nodes/not.c new file mode 100644 index 0000000..81fce28 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/not.c @@ -0,0 +1,416 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * not.c - inversion de résultats de correspondances établis + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "not.h" + + +#include <assert.h> + + +#include "not-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des inversions de correspondances. */ +static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *); + +/* Initialise une instance d'inversion de correspondances. */ +static void g_scan_token_node_not_init(GScanTokenNodeNot *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_not_dispose(GScanTokenNodeNot *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_not_finalize(GScanTokenNodeNot *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Prend acte d'une nouvelle propriété pour le noeud. */ +static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *, ScanTokenNodeFlags); + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +static void g_scan_token_node_not_visit(GScanTokenNodeNot *, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *, GEngineBackend *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une inversion des résultats de correspondances. */ +G_DEFINE_TYPE(GScanTokenNodeNot, g_scan_token_node_not, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des inversions de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_not_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_not_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_not_apply_flags; + node->visit = (visit_scan_token_node_fc)g_scan_token_node_not_visit; + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_not_enroll; + node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_not_build_id; + node->check_forward = (check_scan_token_node_fc)g_scan_token_node_not_check_forward; + node->check_backward = (check_scan_token_node_fc)g_scan_token_node_not_check_backward; + +} + + +/****************************************************************************** +* * +* Paramètres : not = instance à initialiser. * +* * +* Description : Initialise une instance d'inversion de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_init(GScanTokenNodeNot *not) +{ + not->child = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : not = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_dispose(GScanTokenNodeNot *not) +{ + g_clear_object(¬->child); + + G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->dispose(G_OBJECT(not)); + +} + + +/****************************************************************************** +* * +* Paramètres : not = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_finalize(GScanTokenNodeNot *not) +{ + G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->finalize(G_OBJECT(not)); + +} + + +/****************************************************************************** +* * +* Paramètres : child = noeud dont les résultats sont à écarter. * +* * +* Description : Construit une inversion de résultats de correspondances. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *child) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_NOT, NULL); + + if (!g_scan_token_node_not_create(G_SCAN_TOKEN_NODE_NOT(result), child)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : not = encadrement d'inversion à initialiser pleinement. * +* child = noeud dont les résultats sont à écarter. * +* * +* Description : Met en place une inversion de résultats de correspondances. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_not_create(GScanTokenNodeNot *not, GScanTokenNode *child) +{ + bool result; /* Bilan à retourner */ + + result = true; + + not->child = child; + g_object_ref(G_OBJECT(child)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à mettre à jour. * +* flags = propriétés particulières à associer au noeud. * +* * +* Description : Prend acte d'une nouvelle propriété pour le noeud. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *node, ScanTokenNodeFlags flags) +{ + g_scan_token_node_set_flags(node->child, flags); + +} + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à effectuer. * +* points = points capitaux de l'arborescence. [OUT] * +* * +* Description : Parcourt une arborescence de noeuds et y relève des éléments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_points_t *points) +{ + g_scan_token_node_visit(node->child, points); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + + result = _g_scan_token_node_enroll(node->child, backend, maxsize, slow); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + + result = g_scan_token_node_build_id(node->child, backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + +#if 0 + + + bool initialized; /* Initialisation du suivi ? */ + phys_t i; /* Boucle de parcours */ + + + /* + + ????????????????????????? + + + if (*skip) + return; + */ + + + + initialized = are_pending_matches_initialized(matches); + + + //printf("TOTO......(init done? %d)\n", initialized); + + + + if (!initialized) + { + for (i = matches->content_start; i < matches->content_end; i++) + add_pending_match(matches, i, 0); + + set_pending_matches_initialized(matches); + + } + + _g_scan_token_node_check_forward(node->child, context, content, matches, offset, !not, skip); + + +#endif + + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + + + + if (*skip) + return; + + + + printf("TODO\n"); + assert(0); + + + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/not.h b/src/analysis/scan/patterns/tokens/nodes/not.h new file mode 100644 index 0000000..58630e8 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/not.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * not.h - prototypes pour l'inversion de résultats de correspondances établis + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H + + +#include <glib-object.h> + + +#include "../node.h" +#include "../../../../../arch/archbase.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_NOT g_scan_token_node_not_get_type() +#define G_SCAN_TOKEN_NODE_NOT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNot)) +#define G_IS_SCAN_TOKEN_NODE_NOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_NOT)) +#define G_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass)) +#define G_IS_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_NOT)) +#define G_SCAN_TOKEN_NODE_NOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass)) + + +/* Inversion de résultats de correspondances établis (instance) */ +typedef struct _GScanTokenNodeNot GScanTokenNodeNot; + +/* Inversion de résultats de correspondances établis (classe) */ +typedef struct _GScanTokenNodeNotClass GScanTokenNodeNotClass; + + +/* Indique le type défini pour une inversion des résultats de correspondances. */ +GType g_scan_token_node_not_get_type(void); + +/* Construit une inversion de résultats de correspondances. */ +GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/plain-int.h b/src/analysis/scan/patterns/tokens/nodes/plain-int.h new file mode 100644 index 0000000..2077c6f --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/plain-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain-int.h - prototypes internes pour la gestion d'une recherche de motif textuel + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H + + +#include "plain.h" + + +#include "../atom.h" +#include "../node-int.h" + + + +/* Bribe de motif textuelle pour recherches (instance) */ +struct _GScanTokenNodePlain +{ + GScanTokenNode parent; /* A laisser en premier */ + + sized_binary_t orig; /* Motif d'origine avant modifs*/ + GScanTokenModifier *modifier; /* Transformateur pour le motif*/ + ScanPlainNodeFlags flags; /* Fanions associés au motif */ + + sized_binary_t *raw; /* Liste de motifs à couvrir */ + tracked_scan_atom_t *atoms; /* Atomes correspondants */ + size_t count; /* Taille de cette liste */ + +}; + +/* Bribe de motif textuelle pour recherches (instance) */ +struct _GScanTokenNodePlainClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un noeud représentant un motif textuel. */ +bool g_scan_token_node_plain_create(GScanTokenNodePlain *, const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c new file mode 100644 index 0000000..5dd45df --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/plain.c @@ -0,0 +1,1377 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - gestion d'une recherche de motif textuel + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "plain.h" + + +#include <assert.h> + + +#include "plain-int.h" +#include "../../../../../common/extstr.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des noeuds pour motif textuel. */ +static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *); + +/* Initialise une instance de noeud pour motif textuel. */ +static void g_scan_token_node_plain_init(GScanTokenNodePlain *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_plain_dispose(GScanTokenNodePlain *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Communique l'intérêt d'un noeud au sein d'une analyse. */ +static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *); + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +static void g_scan_token_node_plain_visit(GScanTokenNodePlain *, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *, GEngineBackend *); + +/* Détermine si un contenu d'intérêt est présent à une position. */ +static bool check_scan_token_node_plain_content(const sized_binary_t *, const tracked_scan_atom_t *, bool, phys_t, GBinContent *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un noeud représentant une bribe de texte à retrouver. */ +G_DEFINE_TYPE(GScanTokenNodePlain, g_scan_token_node_plain, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des noeuds pour motif textuel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_plain_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_plain_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_plain_compute_weight_for_scan; + node->apply = (apply_scan_token_node_flags_fc)NULL; + node->visit = (visit_scan_token_node_fc)g_scan_token_node_plain_visit; + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_plain_enroll; + node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_plain_build_id; + node->check_forward = (check_scan_token_node_fc)g_scan_token_node_plain_check_forward; + node->check_backward = (check_scan_token_node_fc)g_scan_token_node_plain_check_backward; + +} + + +/****************************************************************************** +* * +* Paramètres : plain = instance à initialiser. * +* * +* Description : Initialise une instance de noeud pour motif textuel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_init(GScanTokenNodePlain *plain) +{ + init_szstr(&plain->orig); + plain->modifier = NULL; + plain->flags = SPNF_NONE; + + plain->raw = NULL; + plain->atoms = NULL; + plain->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : plain = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_dispose(GScanTokenNodePlain *plain) +{ + g_clear_object(&plain->modifier); + + G_OBJECT_CLASS(g_scan_token_node_plain_parent_class)->dispose(G_OBJECT(plain)); + +} + + +/****************************************************************************** +* * +* Paramètres : plain = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *plain) +{ + size_t i; /* Boucle de parcours */ + + exit_szstr(&plain->orig); + + for (i = 0; i < plain->count; i++) + exit_szstr(&plain->raw[i]); + + if (plain->raw != NULL) + free(plain->raw); + + if (plain->atoms != NULL) + free(plain->atoms); + + G_OBJECT_CLASS(g_scan_token_node_plain_parent_class)->finalize(G_OBJECT(plain)); + +} + + +/****************************************************************************** +* * +* Paramètres : text = texte brut à rechercher. * +* modifier = transformateur éventuel à solliciter. * +* flags = particularités à prendre en considération. * +* * +* Description : Construit un noeud représentant un motif textuel. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainNodeFlags flags) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_PLAIN, NULL); + + if (!g_scan_token_node_plain_create(G_SCAN_TOKEN_NODE_PLAIN(result), text, modifier, flags)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plain = encadrement de motif à initialiser pleinement. * +* text = texte brut à rechercher. * +* modifier = transformateur éventuel à solliciter. * +* flags = particularités à prendre en considération. * +* * +* Description : Met en place un noeud représentant un motif textuel. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainNodeFlags flags) +{ + bool result; /* Bilan à retourner */ + + result = true; + + szstrdup(&plain->orig, text); + + if (modifier != NULL) + { + plain->modifier = modifier; + g_object_ref(G_OBJECT(modifier)); + } + + plain->flags = flags; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plain = noeud de motif textuel à consulter. * +* * +* Description : Indique les propriétés particulières d'un noeud de texte. * +* * +* Retour : Propriétés particulières associées au noeud. * +* * +* Remarques : - * +* * +******************************************************************************/ + +ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *plain) +{ + ScanPlainNodeFlags result; /* Statut à retourner */ + + result = plain->flags; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à consulter. * +* index = indice de la combinaison de modificateurs ciblée. * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node, size_t index) +{ + char *result; /* Combinaison à retourner */ + + if (node->modifier == NULL) + result = strdup("plain"); + + else + result = g_scan_token_modifier_get_path(node->modifier, (size_t []){ index }); + + return result; + + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à consulter. * +* * +* Description : Communique l'intérêt d'un noeud au sein d'une analyse. * +* * +* Retour : Poids de l'importance pour un départ de scan. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *node) +{ + float result; /* Valeur à retourner */ + + result = node->orig.len; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à effectuer. * +* points = points capitaux de l'arborescence. [OUT] * +* * +* Description : Parcourt une arborescence de noeuds et y relève des éléments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_points_t *points) +{ + GScanTokenNode *candidate; /* Autre version du noeud */ + float node_weight; /* Poids du noeud courant */ + float other_weight; /* Poids de l'autre noeud */ + + if (points->first_plain == NULL) + points->first_plain = G_SCAN_TOKEN_NODE(node); + + else + { + candidate = G_SCAN_TOKEN_NODE(node); + + node_weight = g_scan_token_node_compute_weight_for_scan(candidate); + other_weight = g_scan_token_node_compute_weight_for_scan(points->first_plain); + + if (node_weight >= other_weight) + points->first_plain = candidate; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* context = contexte de l'analyse à mener. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + tracked_scan_atom_t atom; /* Atome identifié */ + size_t letters; /* Nombre de lettres présentes */ + size_t k; /* Boucle de parcours #2 */ + size_t extra_count; /* Quantité pour l'exhaustivité*/ + sized_binary_t *extra; /* Couverture supplémntaire */ + size_t remaining; /* Quantité restant à traiter */ + + /* Génération d'une base de chaînes à couvrir */ + + if (node->modifier == NULL) + { + node->raw = malloc(sizeof(sized_binary_t)); + node->count = 1; + + szstrdup(&node->raw[0], &node->orig); + + result = true; + + } + else + result = g_scan_token_modifier_transform(node->modifier, &node->orig, 1, &node->raw, &node->count); + + if (!result) + goto exit; + + /* Préparation pour la mémorisation des atomes */ + + node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t)); + + /* Validation du besoin effectif dans les cas extrèmes */ + + + + // TODO : if (orig.len < ...) + + + + /* Recherche des atomes */ + + for (i = 0; i < node->count; i++) + { + if (node->flags & SPNF_CASE_INSENSITIVE) + { + find_best_atom(&node->raw[i], maxsize, &atom, &letters); + + if (letters == 0) + node->atoms[i] = atom; + + /* Insertion des nouvelles combinaisons pour couvrir toutes les casses */ + else + { + /* extra_count = 2^letters */ + for (k = 1, extra_count = 2; k < letters; k++, extra_count *= 2) + ; + + extra = make_atoms_case_insensitive(&node->raw[i], &atom, extra_count); + + remaining = node->count - i - 1; + + node->count += (extra_count - 1); + + node->raw = realloc(node->raw, node->count * sizeof(sized_binary_t)); + + memmove(&node->raw[i + extra_count], &node->raw[i + 1], remaining * sizeof(sized_binary_t)); + + for (k = 0; k < extra_count; k++) + node->raw[i + k] = extra[k]; + + free(extra); + + node->atoms = realloc(node->atoms, node->count * sizeof(tracked_scan_atom_t)); + + for (k = 0; k < extra_count; k++) + node->atoms[i + k] = atom; + + i += extra_count - 1; + + } + + } + + else + find_best_atom(&node->raw[i], maxsize, &node->atoms[i], &letters); + + } + + /* Enregistrements en masse */ + + for (i = 0; i < node->count && result; i++) + result = enroll_prepared_atom(&node->raw[i], backend, &node->atoms[i]); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + + result = true; + + for (i = 0; i < node->count && result; i++) + result = build_atom_pattern_id(&node->atoms[i], backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = contneu brut à retrouver idéalement. * +* atom = contenu brut représentatif ciblé. * +* nocase = marque un éventuel désintérêt pour la casse. * +* start = point d'analyse à respecter. * +* content = accès au contenu brut pour vérifications (optim.) * +* * +* Description : Détermine si un contenu d'intérêt est présent à une position.* +* * +* Retour : Bilan de l'analyse : true pour une correspondance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, bool nocase, phys_t start, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + vmpa2t pos; /* Position dans les données */ + const bin_t *ptr; /* Accès aux données brutes */ + int ret; /* Bilan d'une comparaison */ + + result = false; + + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); + + /* Validation du motif intégral */ + + if (atom == NULL) + { + ptr = g_binary_content_get_raw_access(content, &pos, raw->len); + + /** + * Si la partion atomique recherchée est trouvée en début de contenu, + * le reste du motif de recherche va déborder. L'accès correspondant + * est donc refusé, et cette situation est prise en compte ici. + */ + if (ptr == NULL) goto done; + + if (nocase) + ret = memcasecmp(raw->data, ptr, raw->len); + else + ret = memcmp(raw->data, ptr, raw->len); + + result = (ret == 0); + + } + + /* Validation des extrémités */ + + else + { + /* Validation du contenu avant l'atome */ + + if (atom->pos > 0) + { + ptr = g_binary_content_get_raw_access(content, &pos, atom->pos); + + /** + * Si la partion atomique recherchée est trouvée en début de contenu, + * le reste du motif de recherche va déborder. L'accès correspondant + * est donc refusé, et cette situation est prise en compte ici. + */ + if (ptr == NULL) goto done; + + if (nocase) + ret = memcasecmp(raw->data, ptr, atom->pos); + else + ret = memcmp(raw->data, ptr, atom->pos); + + if (ret != 0) goto done; + + } + + /* Validation du contenu après l'atome */ + + if (atom->rem > 0) + { + advance_vmpa(&pos, atom->len); + + ptr = g_binary_content_get_raw_access(content, &pos, atom->rem); + + /** + * Si la partion atomique recherchée est trouvée en fin de contenu, + * le reste du motif de recherche va déborder. L'accès correspondant + * est donc refusé, et cette situation est prise en compte ici. + */ + if (ptr == NULL) goto done; + + if (nocase) + ret = memcasecmp(raw->data + atom->pos + atom->len, ptr, atom->rem); + else + ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem); + + if (ret != 0) goto done; + + } + + result = true; + + } + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + bool track_path; /* Conservation du chemin */ + bool nocase; /* Pas d'intérêt pour la casse */ + match_area_t **areas; /* Liste de zones à constituer */ + size_t *count; /* Taille de cette liste */ + bool copy; /* Besoin d'une copie ? */ + bool inverted; /* Inversion des bilans ? */ + size_t i; /* Boucle de parcours #1 */ + const tracked_scan_atom_t *atom; /* Atome correspondant */ + match_area_t *atoms; /* Localisations des bribes */ + bool first_round; /* Premier tour de traitement */ + match_area_t *area; /* Correspondance à valider */ + const sized_binary_t *raw; /* Données brutes d'origine */ + match_area_t *next; /* Correspondance suivante */ + phys_t start; /* Début potentiel de motif */ + bool status; /* Bilan d'une correspondance */ + phys_t after; /* Espace disposible après */ + phys_t min_end; /* Fin la plus proche possible */ + phys_t max_end; /* Fin la plus éloignée trouvée*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN); + + nocase = (node->flags & SPNF_CASE_INSENSITIVE); + + /** + * Création de premières marques de correspondances. + */ + if (!params->initialized) + { + /* Destinations établies une fois pour toutes */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + areas = ¶ms->kept_areas; + count = ¶ms->kept_count; + + copy = false; + inverted = true; + + } + + else if (cflags & TNCF_CREATE_NEW) + { + areas = ¶ms->created_areas; + count = ¶ms->created_count; + + copy = true; + inverted = false; + + } + + else + { + assert(cflags & TNCF_UPDATE_IN_PLACE); + + areas = ¶ms->main_areas; + count = ¶ms->main_count; + + copy = false; + inverted = false; + + } + + /* Parcours des combinaisons enregistrées */ + + for (i = 0; i < node->count; i++) + { + atom = &node->atoms[i]; + + atoms = g_scan_context_get_atom_matches(params->context, atom->pid); + + first_round = (*count == 0); + + if (atom->fast_check) + { + /** + * Toutes les correspondances sont validées d'office car le motif identifié + * correspondant au motif complet. + */ + + if (!inverted) + { + for_each_match_area(area, atoms) + { + /** + * La modification de la zone d'origine est possible dans tous les cas + * car cette zone a été allouée de façon dédiée à un type de correspondances + * et ne sera pas réutilisée comme autre source de correspondance ailleurs. + */ + + assert(area->end >= atom->len); + + area->start = area->end - atom->len; + + (*count)++; + + } + + } + + else + atoms = NULL; + + } + + else + { + raw = &node->raw[i]; + + for_each_match_area_safe(area, &atoms, next) + { + start = area->end - atom->len - atom->pos; + + status = check_scan_token_node_plain_content(raw, atom, nocase, start, params->content); + + if (status) + { + /** + * La modification de la zone d'origine est possible dans tous les cas + * car cette zone a été allouée de façon dédiée à un type de correspondances + * et ne sera pas réutilisée comme autre source de correspondance ailleurs. + */ + + if (!inverted) + { + area->start = start; + area->end += atom->rem; + + (*count)++; + + } + else + del_match_area(area, &atoms); + + } + + else + { + /** + * Les principes de modifications restent valables, même inversés. + */ + if (inverted) + { + area->start = start; + area->end += atom->rem; + + (*count)++; + + } + else + del_match_area(area, &atoms); + + } + + } + + + } + + /* Mise à jour de la liste */ + + if (atoms != NULL) + { + if (first_round) + *areas = atoms; + + else + merge_match_areas(areas, &atoms); + + } + + } + + } + + /** + * Poursuite des traitements sur des correspondances déjà amorcées, impliquant + * des comparaisons entières de motifs. + */ + else + { + if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(area->end <= params->content_end); + + after = params->content_end - area->end; + + if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + /** + * Il ne peut y avoir qu'une seule séquence d'octets à un même + * emplacement. En revanche, des modificateurs peuvent construire + * possédant une même base, mais offrant des suffixes différents + * (par exemple, un marqueur nul UTF-16 final en complément). + * + * L'ensemble des combinaisons produites doit ainsi être exploré. + */ + + /** + * Par ailleurs, même si une base de couples uniques est assurée, + * la constitution d'un ensemble de noeuds peut amener une redondance + * dans les emplacements de correspondances ; ces doublons éventuels + * sont alors filtrés par un appel à sort_match_areas_no_dup(). + * + * Par exemple, pour la séquence d'octets analysés suivante : + * + * aaa....bbb + * + * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir + * les correspondances suivantes : + * + * aa.....bbb -> couple pending[x] (0;2) puis (0;10) + * ^ + * aa....bbb -> couple pending[y] (1;3) puis (1;10) + * ^ + * aaa....bbb -> couple pending[z] (0;3) puis (0;10) + * ^ + * + * Par ailleurs, une même base de départ peut conduire à plusieurs + * zones de correspondances. + * + * Par exemple, pour la séquence d'octets analysés suivante : + * + * aa..bb..bb + * + * La définition { 61 61 [2-6] 62 62 } peut établir + * les correspondances suivantes : + * + * aa..bb..bb -> couple pending[x] (0;2) puis (0;6) + * ^ + * aa..bb..bb -> couple pending[x] (0;2) puis (0;10) + * ^ + */ + + /** + * Dans la première situation, c'est la bribe 62 62 62 qui fait l'objet + * d'une recherche de motifs. Les autres bribes sont recherchées + * manuellement ici, car l'espace de séparation est léger (inférieur à + * MAX_RANGE_FOR_MANUAL_CHECK). + * + * La seconde situation bénéficie de recherches automatisées pour + * l'ensemble des motifs, du fait d'une valeur de séparation plus + * importante. + * + * Dans les deux cas, l'espace de séparation est entièrement considéré. + * La sélection de la correspondance à retour s'établit selon un + * paramètre de configuation : doit-on être avare sur les distances + * consommées ou non ? + */ + + min_end = params->content_end; + max_end = params->content_start; + + updated = false; + + for (i = 0; i < node->count; i++) + { + raw = &node->raw[i]; + + /* Souplesse dans les positions ? */ + if (offsets_exist(¶ms->offset)) + { + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + + for (r = 0; r < rcount; r++) + { + assert(ranges[r].has_max); + assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK); + + for (p = ranges[r].min; p <= ranges[r].max; p++) + { + /** + * Si la fin d'une correspondance potentielle est trop près de + * la fin du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if ((p + raw->len) > after) + break; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, + area->end + p, params->content); + + if (status) + { + updated_edge = area->end + p + raw->len; + + if (updated_edge < min_end) + min_end = updated_edge; + + if (updated_edge > max_end) + max_end = updated_edge; + + updated = true; + + } + + } + + } + + } + + /* Position immédiatement attendue */ + else + { + /** + * Si la fin d'une correspondance potentielle est trop près de + * la fin du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if (raw->len > after) + continue; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, area->end, params->content); + + if (status) + { + updated_edge = area->end + raw->len; + + if (updated_edge < min_end) + min_end = updated_edge; + + if (updated_edge > max_end) + max_end = updated_edge; + + updated = true; + + } + + } + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->end = (1 /* greedy */ ? min_end : max_end); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + } + + params->initialized = true; + + disable_all_ranges_in_node_search_offset(¶ms->offset); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + + + + + + bool track_path; /* Conservation du chemin */ + bool nocase; /* Pas d'intérêt pour la casse */ + + + + + size_t i; /* Boucle de parcours #1 */ + + + const sized_binary_t *raw; /* Données brutes d'origine */ + + + bool status; /* Bilan d'une correspondance */ + + + + + + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t before; /* Espace disposible avant */ + phys_t min_start; /* Début le plus proche trouvé */ + phys_t max_start; /* Début le plus distant trouvé*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + + if (*skip) + return; + + /** + * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors + * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu. + */ + + assert(params->initialized); + + track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN); + + nocase = (node->flags & SPNF_CASE_INSENSITIVE); + + + + /** + * ............. + */ + if (0) + { + + + ; + + + + } + + /** + * Poursuite des traitements sur des correspondances déjà amorcées, impliquant + * des comparaisons entières de motifs. + */ + else + { + if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(params->content_start <= area->start); + + before = area->start - params->content_start; + + if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + /** + * Il ne peut y avoir qu'une seule séquence d'octets à un même + * emplacement. En revanche, des modificateurs peuvent construire + * possédant une même base, mais offrant des suffixes différents + * (par exemple, un marqueur nul UTF-16 final en complément). + * + * L'ensemble des combinaisons produites doit ainsi être exploré. + */ + + min_start = params->content_start; + max_start = params->content_end; + + updated = false; + + for (i = 0; i < node->count; i++) + { + raw = &node->raw[i]; + + /* Souplesse dans les positions ? */ + if (offsets_exist(¶ms->offset)) + { + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + + for (r = 0; r < rcount; r++) + { + assert(ranges[r].has_max); + assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK); + + for (p = ranges[r].min; p <= ranges[r].max; p++) + { + /** + * Si la fin d'une correspondance potentielle est trop près de + * la fin du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if ((p + raw->len) > before) + break; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, + area->start - raw->len - p, + params->content); + + if (status) + { + updated_edge = area->start - raw->len - p; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (updated_edge < max_start) + max_start = updated_edge; + + updated = true; + + } + + } + + } + + } + + /* Position immédiatement attendue */ + else + { + /** + * Si la fin d'une correspondance potentielle est trop près du + * début du contenu binaire et ne peut contenir le motif + * représenté, alors la corresponance est écartée sans appel. + */ + if (raw->len > before) + continue; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, + area->start - raw->len, + params->content); + + if (status) + { + updated_edge = area->start - raw->len; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (updated_edge < max_start) + max_start = updated_edge; + + updated = true; + + } + + } + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->start = (1 /* greedy */ ? min_start : max_start); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + } + + disable_all_ranges_in_node_search_offset(¶ms->offset); + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h new file mode 100644 index 0000000..abf71de --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/plain.h @@ -0,0 +1,83 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - prototypes pour la gestion d'une recherche de motif textuel + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H + + +#include <glib-object.h> + + +#include "../node.h" +#include "../../modifier.h" +#include "../../../../../common/szstr.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_PLAIN g_scan_token_node_plain_get_type() +#define G_SCAN_TOKEN_NODE_PLAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlain)) +#define G_IS_SCAN_TOKEN_NODE_PLAIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN)) +#define G_SCAN_TOKEN_NODE_PLAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlainClass)) +#define G_IS_SCAN_TOKEN_NODE_PLAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_PLAIN)) +#define G_SCAN_TOKEN_NODE_PLAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlainClass)) + + +/* Bribe de motif textuelle pour recherches (instance) */ +typedef struct _GScanTokenNodePlain GScanTokenNodePlain; + +/* Bribe de motif textuelle pour recherches (classe) */ +typedef struct _GScanTokenNodePlainClass GScanTokenNodePlainClass; + + +/* Propriétés d'un élément textuel à rechercher */ +typedef enum _ScanPlainNodeFlags +{ + SPNF_NONE = (0 << 0), /* Aucune particularité */ + SPNF_CASE_INSENSITIVE = (1 << 0), /* Ignorance de la casse */ + + /** + * Les deux propriétés suivantes sont récupérées et traitées + * au niveau du Token propriétaire. + */ + + SPNF_FULLWORD = (1 << 1), /* Recherche de mot entier */ + SPNF_PRIVATE = (1 << 2), /* Marque privative */ + +} ScanPlainNodeFlags; + + +/* Indique le type défini pour un noeud représentant une bribe de texte à retrouver. */ +GType g_scan_token_node_plain_get_type(void); + +/* Construit un noeud représentant un motif textuel. */ +GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags); + +/* Indique les propriétés particulières d'un noeud de texte. */ +ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *, size_t); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence-int.h b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h new file mode 100644 index 0000000..f0ea6ae --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sequence-int.h - prototypes internes pour des décompositions séquentielles de motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H + + +#include "sequence.h" + + +#include "../node-int.h" + + + +/* Décompositions séquentielles de motif de recherche (instance) */ +struct _GScanTokenNodeSequence +{ + GScanTokenNode parent; /* A laisser en premier */ + + GScanTokenNode **children; /* Sous-noeuds à représenter */ + size_t count; /* Taille de cette liste */ + +}; + +/* Décompositions séquentielles de motif de recherche (classe) */ +struct _GScanTokenNodeSequenceClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une série de décompositions séquentielles. */ +bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *, GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.c b/src/analysis/scan/patterns/tokens/nodes/sequence.c new file mode 100644 index 0000000..394c877 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c @@ -0,0 +1,504 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sequence.c - décompositions séquentielles de motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "sequence.h" + + +#include <assert.h> + + +#include "any.h" +#include "sequence-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des décompositions séquentielles. */ +static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *); + +/* Initialise une instance de décompositions séquentielles. */ +static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Prend acte d'une nouvelle propriété pour le noeud. */ +static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *, ScanTokenNodeFlags); + +/* Parcourt une arborescence de noeuds et y relève des éléments. */ +static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *, GEngineBackend *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */ +G_DEFINE_TYPE(GScanTokenNodeSequence, g_scan_token_node_sequence, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des décompositions séquentielles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_sequence_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_sequence_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_sequence_apply_flags; + node->visit = (visit_scan_token_node_fc)g_scan_token_node_sequence_visit; + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_sequence_enroll; + node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_sequence_build_id; + node->check_forward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_forward; + node->check_backward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_backward; + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = instance à initialiser. * +* * +* Description : Initialise une instance de décompositions séquentielles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *sequence) +{ + sequence->children = NULL; + sequence->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *sequence) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < sequence->count; i++) + g_clear_object(&sequence->children[i]); + + G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->dispose(G_OBJECT(sequence)); + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *sequence) +{ + if (sequence->children != NULL) + free(sequence->children); + + G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->finalize(G_OBJECT(sequence)); + +} + + +/****************************************************************************** +* * +* Paramètres : child = noeud dont les résultats sont à écarter. * +* * +* Description : Construit une série de décompositions séquentielles de motif.* +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *child) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, NULL); + + if (!g_scan_token_node_sequence_create(G_SCAN_TOKEN_NODE_SEQUENCE(result), child)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = décompositions à initialiser pleinement. * +* child = noeud dont les résultats sont à écarter. * +* * +* Description : Met en place une série de décompositions séquentielles. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *sequence, GScanTokenNode *child) +{ + bool result; /* Bilan à retourner */ + + result = true; + + g_scan_token_node_sequence_add(sequence, child); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = ensemble de noeuds à compléter. * +* child = nouveau noeud à intégrer. * +* * +* Description : Ajoute un noeud à aux décompositions séquentielles de motif. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_sequence_add(GScanTokenNodeSequence *sequence, GScanTokenNode *child) +{ + bool processed; /* Intégration traitée ? */ + GScanTokenNode *last; /* Dernier noeud inscrit */ + + processed = false; + + if (sequence->count > 0) + { + last = sequence->children[sequence->count - 1]; + + if (G_IS_SCAN_TOKEN_NODE_ANY(last) && G_IS_SCAN_TOKEN_NODE_ANY(child)) + { + g_scan_token_node_any_merge(G_SCAN_TOKEN_NODE_ANY(last), G_SCAN_TOKEN_NODE_ANY(child)); + processed = true; + } + + } + + if (!processed) + { + sequence->children = realloc(sequence->children, ++sequence->count * sizeof(GScanTokenNode *)); + + sequence->children[sequence->count - 1] = child; + g_object_ref(G_OBJECT(child)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = ensemble de noeuds à consulter. * +* * +* Description : Indique le nombre de noeuds intégrés dans la séquence. * +* * +* Retour : Nombre de noeuds représentés. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_scan_token_node_sequence_count(const GScanTokenNodeSequence *sequence) +{ + size_t result; /* Quantité à retourner */ + + result = sequence->count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : sequence = ensemble de noeuds à consulter. * +* index = indice du noeud à retourner. * +* * +* Description : Fournit un noeud donné d'une décomposition séquentielle. * +* * +* Retour : Noeud inclus dans l'ensemble ou NULL si mauvais indice. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_sequence_get(const GScanTokenNodeSequence *sequence, size_t index) +{ + GScanTokenNode *result; /* Instance à retourner */ + + assert(index < sequence->count); + + if (index < sequence->count) + { + result = sequence->children[index]; + g_object_ref(G_OBJECT(result)); + } + + else + result = NULL; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = noeud de motif à mettre à jour. * +* flags = propriétés particulières à associer au noeud. * +* * +* Description : Prend acte d'une nouvelle propriété pour le noeud. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *node, ScanTokenNodeFlags flags) +{ + size_t i; /* Boucle de parcours */ + + if (node->count == 1) + g_scan_token_node_set_flags(node->children[0], flags); + + else if (node->count > 1) + { + g_scan_token_node_set_flags(node->children[0], flags & ~STNF_LAST); + + for (i = 1; i < (node->count - 1); i++) + g_scan_token_node_set_flags(node->children[i], flags & ~(STNF_FIRST | STNF_LAST)); + + g_scan_token_node_set_flags(node->children[node->count - 1], flags & ~STNF_FIRST); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = point de départ du parcours à effectuer. * +* points = points capitaux de l'arborescence. [OUT] * +* * +* Description : Parcourt une arborescence de noeuds et y relève des éléments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *points) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < node->count; i++) + g_scan_token_node_visit(node->children[i], points); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* slow = niveau de ralentissement induit (0 = idéal). [OUT] * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GEngineBackend *backend, size_t maxsize, size_t *slow) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < node->count && result; i++) + result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + + result = true; + + for (i = 0; i < node->count && result; i++) + result = g_scan_token_node_build_id(node->children[i], backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < node->count; i++) + _g_scan_token_node_check_forward(node->children[i], params, cflags, skip); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) +{ + size_t i; /* Boucle de parcours */ + + for (i = node->count; i > 0 ; i--) + _g_scan_token_node_check_backward(node->children[i - 1], params, cflags, skip); + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.h b/src/analysis/scan/patterns/tokens/nodes/sequence.h new file mode 100644 index 0000000..12df9d1 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/sequence.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sequence.h - prototypes pour des décompositions séquentielles de motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H + + +#include <glib-object.h> + + +#include "../node.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_SEQUENCE g_scan_token_node_sequence_get_type() +#define G_SCAN_TOKEN_NODE_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequence)) +#define G_IS_SCAN_TOKEN_NODE_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE)) +#define G_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass)) +#define G_IS_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE)) +#define G_SCAN_TOKEN_NODE_SEQUENCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass)) + + +/* Décompositions séquentielles de motif de recherche (instance) */ +typedef struct _GScanTokenNodeSequence GScanTokenNodeSequence; + +/* Décompositions séquentielles de motif de recherche (classe) */ +typedef struct _GScanTokenNodeSequenceClass GScanTokenNodeSequenceClass; + + +/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */ +GType g_scan_token_node_sequence_get_type(void); + +/* Construit une série de décompositions séquentielles de motif. */ +GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *); + +/* Ajoute un noeud à aux décompositions séquentielles de motif. */ +void g_scan_token_node_sequence_add(GScanTokenNodeSequence *, GScanTokenNode *); + +/* Indique le nombre de noeuds intégrés dans la séquence. */ +size_t g_scan_token_node_sequence_count(const GScanTokenNodeSequence *); + +/* Fournit un noeud donné d'une décomposition séquentielle. */ +GScanTokenNode *g_scan_token_node_sequence_get(const GScanTokenNodeSequence *, size_t); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H */ diff --git a/src/analysis/scan/patterns/tokens/offset.c b/src/analysis/scan/patterns/tokens/offset.c new file mode 100644 index 0000000..0a4fd91 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/offset.c @@ -0,0 +1,438 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * offset.c - décomposition d'un motif de recherche en atomes assemblés + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "offset.h" + + +#include <assert.h> + + + + + + +/****************************************************************************** +* * +* Paramètres : range = bornes décrivant un espace quelconque. * +* available = espace restant disponible. * +* min = point de départ pour parcourir une zone. [OUT] * +* max = point d'arrivée pour parcourir une zone. [OUT] * +* * +* Description : Fournit les bornes d'une zone à analyser. * +* * +* Retour : true si assez d'espace est disponible, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool get_node_offset_range(const node_offset_range_t *range, phys_t len, phys_t available, phys_t *min, phys_t *max) +{ + bool result; /* Bilan à retourner */ + + if ((len + range->min) > available) + result = false; + + else + { + result = true; + + *min = range->min; + *max = range->max; + + if ((len + *max) > available) + { + *max = available - len; + assert(*max >= *min); + } + + } + + return result; + +} + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à initialiser. * +* * +* Description : Initialise une mémorisation d'intervales de tolérance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void init_node_search_offset(node_search_offset_t *offset) +{ + offset->ranges = NULL; + offset->allocated = 0; + + offset->gen_ptr = NULL; + + offset->used = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] * +* src = suivi de tolérances bornées à copier. * +* * +* Description : Copie une mémorisation d'intervales entre positions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void copy_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src) +{ + init_node_search_offset(dest); + + switch (src->used) + { + case 0: + dest->gen_ptr = NULL; + break; + + case 1: + dest->range = src->range; + dest->gen_ptr = &dest->range; + break; + + default: + dest->ranges = malloc(src->used * sizeof(node_offset_range_t)); + memcpy(dest->ranges, src->ranges, src->used * sizeof(node_offset_range_t)); + dest->gen_ptr = dest->ranges;; + break; + + } + + dest->used = src->used; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] * +* src = suivi de tolérances bornées à copier. * +* * +* Description : Fusionne une mémorisation d'intervales entre positions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void merge_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src) +{ + node_offset_range_t * const *list; /* Liste d'intervales à copier */ + size_t i; /* Boucle de parcours */ + + if ((dest->used + src->used) > 1 && (dest->used + src->used) > dest->allocated) + { + dest->allocated += src->used; + + dest->ranges = realloc(dest->ranges, dest->allocated * sizeof(node_offset_range_t)); + + } + + list = get_node_search_offset_ranges(src, (size_t []){ 0 }); + + for (i = 0; i < src->used; i++) + add_range_to_node_search_offset(dest, (*list)[i].min, (*list)[i].max, NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à terminer. * +* * +* Description : Met fin à une mémorisation d'intervales de tolérance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void exit_node_search_offset(node_search_offset_t *offset) +{ + if (offset->ranges != NULL) + free(offset->ranges); + +} + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à consulter. * +* count = nombre de bornes enregistrées. [OUT] * +* * +* Description : Fournit la liste des tolérances bornées établies à présent. * +* * +* Retour : Liste d'intervales en lecture seule. * +* * +* Remarques : - * +* * +******************************************************************************/ + +node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *offset, size_t *count) +{ + node_offset_range_t * const *result; /* Série à renvoyer */ + + result = &offset->gen_ptr; + + *count = offset->used; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à consulter. * +* count = nombre de bornes enregistrées. [OUT] * +* * +* Description : Fournit la liste des tolérances bornées établies à présent. * +* * +* Retour : Liste d'intervales en lecture seule. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *offset, size_t *count) +{ + node_offset_range_t *result; /* Série à renvoyer */ + + result = offset->gen_ptr; + + *count = offset->used; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à consulter. * +* min = point de départ pour parcourir une zone. * +* max = point d'arrivée pour parcourir une zone. * +* datasize = taille maximale pour définir une inversion NOT. * +* * +* Description : Ajoute un nouvel espace borné aux décalages tolérés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void add_range_to_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, const phys_t *datasize) +{ + bool not; /* Traduction de la taille */ + size_t needed; /* Nombre d'emplacements requis*/ + + not = (datasize != NULL); + + /* Si le réceptacle unique peut être employé... */ + if (offset->used == 0 && !not) + { + offset->range.min = min; + offset->range.max = max; + + offset->used = 1; + + offset->gen_ptr = &offset->range; + + } + + /* Sinon le groupe dynamique est sollicité */ + else + { + needed = offset->used + (not ? 2 : 1); + + if (needed > offset->allocated) + { + offset->ranges = realloc(offset->ranges, needed * sizeof(node_offset_range_t)); + offset->allocated = needed; + } + + /* Bascule d'un éventuel intervale courant */ + if (offset->used == 1) + { + offset->ranges[0].min = offset->range.min; + offset->ranges[0].max = offset->range.max; + } + + if (not) + { + if (min > 0) + { + offset->ranges[offset->used].min = 0; + offset->ranges[offset->used].max = min - 1; + + offset->used++; + + } + + if ((max + 1) < *datasize) + { + offset->ranges[offset->used].min = max + 1; + offset->ranges[offset->used].max = *datasize - (max + 1); + + offset->used++; + + } + + } + else + { + offset->ranges[offset->used].min = min; + offset->ranges[offset->used].max = max; + + offset->used++; + + } + + offset->gen_ptr = offset->ranges; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à consulter. * +* min = point de départ pour parcourir une zone. * +* max = point d'arrivée pour parcourir une zone. * +* has_max = validité de la valeur maximale transmise. * +* * +* Description : Etend les décalages tolérés avec un nouvel espace. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void extend_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, bool has_max) +{ + size_t i; /* Boucle de parcours */ + + switch (offset->used) + { + /* Si le réceptacle unique peut être employé... */ + case 0: + + offset->range.min = min; + offset->range.max = max; + offset->range.has_max = has_max; + + offset->used = 1; + + offset->gen_ptr = &offset->range; + + break; + + /* Si un espace unique est enregistré */ + case 1: + + offset->range.min += min; + offset->range.max += max; + offset->range.has_max &= has_max; + + break; + + /* Sinon le groupe dynamique est sollicité */ + default: + + for (i = 0; i < offset->used; i++) + { + offset->ranges[i].min += min; + offset->ranges[i].max += max; + offset->ranges[i].has_max &= has_max; + } + + break; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : offset = suivi de tolérances bornées à consulter. * +* last = dernière position validée. * +* pos = nouvelle position potentielle. * +* * +* Description : Indique si une position est comprise dans un intervale. * +* * +* Retour : Bilan de la détermination. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool does_node_search_offset_include_pos_forward(const node_search_offset_t *offset, phys_t last, phys_t pos) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + const node_offset_range_t *range; /* Accès rapide aux infos. */ + + result = false; + + for (i = 0; i < offset->used; i++) + { + range = &offset->gen_ptr[i]; + + result = ((last + range->min) <= pos && pos <= (last + range->max)); + if (result) break; + + } + + return result; + +} diff --git a/src/analysis/scan/patterns/tokens/offset.h b/src/analysis/scan/patterns/tokens/offset.h new file mode 100644 index 0000000..130aaea --- /dev/null +++ b/src/analysis/scan/patterns/tokens/offset.h @@ -0,0 +1,111 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * offset.h - prototypes pour la prise en compte des espaces entre octets dans un motif de recherche + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H + + +#include <stdbool.h> + +#include "../../../../arch/vmpa.h" + + + +/* Mémorisation d'une souplesse dans les positions visées */ +typedef struct _node_offset_range_t +{ + /** + * Les deux champs ci-après font bien référence à des positions absolues, + * et non à des bornes d'espace, lorsque les résultats de correspondances + * sont encore non initialisés. + * + * Ensuite ces bornes représentent bien un espace séparant les résultats + * issus de deux noeuds. + */ + phys_t min; /* Position minimale */ + phys_t max; /* Position maximale */ + bool has_max; /* Quantité définie ? */ + +} node_offset_range_t; + + +/* Fournit les bornes d'une zone à analyser. */ +bool get_node_offset_range(const node_offset_range_t *, phys_t, phys_t, phys_t *, phys_t *); + + + +#define MAX_RANGE_FOR_MANUAL_CHECK 5 + + + +/* Mémorisation d'une souplesse dans les positions visées */ +typedef struct _node_search_offset_t +{ + node_offset_range_t range; /* Bornes de décalage uniques */ + + node_offset_range_t *ranges; /* Bornes de décalage multiples*/ + size_t allocated; /* Nombre d'allocations */ + + node_offset_range_t *gen_ptr; /* Accès générique à la liste */ + + size_t used; /* Nombre de bornes présentes */ + +} node_search_offset_t; + + +/* Initialise une mémorisation d'intervales de tolérance. */ +void init_node_search_offset(node_search_offset_t *); + +/* Copie une mémorisation d'intervales entre positions. */ +void copy_node_search_offset(node_search_offset_t *, const node_search_offset_t *); + +/* Fusionne une mémorisation d'intervales entre positions. */ +void merge_node_search_offset(node_search_offset_t *, const node_search_offset_t *); + +/* Met fin à une mémorisation d'intervales de tolérance. */ +void exit_node_search_offset(node_search_offset_t *); + +#define offsets_exist(off) \ + ((off)->used > 0) + + +/* Fournit la liste des tolérances bornées établies à présent. */ +/* TODO : supprimer un niveau d'indirection */ +node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *, size_t *); +const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *, size_t *); + +/* Ajoute un nouvel espace borné aux décalages tolérés. */ +void add_range_to_node_search_offset(node_search_offset_t *, phys_t, phys_t, const phys_t *); + +/* Etend les décalages tolérés avec un nouvel espace. */ +void extend_node_search_offset(node_search_offset_t *, phys_t, phys_t, bool); + +#define disable_all_ranges_in_node_search_offset(off) \ + (off)->used = 0 + +/* Indique si une position est comprise dans un intervale. */ +bool does_node_search_offset_include_pos_forward(const node_search_offset_t *, phys_t, phys_t); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H */ diff --git a/src/analysis/scan/patterns/tokens/plain-int.h b/src/analysis/scan/patterns/tokens/plain-int.h new file mode 100644 index 0000000..b0ef106 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/plain-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain-int.h - prototypes internes pour la recherche d'une chaîne de caractères brute + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H + + +#include "plain.h" + + +#include "atom.h" +#include "../token-int.h" + + + +/* Encadrement d'une recherche de texte brut (instance) */ +struct _GScanPlainBytes +{ + GBytesToken parent; /* A laisser en premier */ + +}; + +/* Encadrement d'une recherche de texte brut (classe) */ +struct _GScanPlainBytesClass +{ + GBytesTokenClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un gestionnaire de recherche de texte brut. */ +bool g_scan_plain_bytes_create(GScanPlainBytes *, GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c new file mode 100644 index 0000000..3d6c39d --- /dev/null +++ b/src/analysis/scan/patterns/tokens/plain.c @@ -0,0 +1,266 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - recherche d'une chaîne de caractères brute + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "plain.h" + + +#include <malloc.h> +#include <string.h> + + +#include "plain-int.h" +#include "nodes/plain.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des recherches de texte brut. */ +static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass); + +/* Initialise une instance de recherche de texte brut. */ +static void g_scan_plain_bytes_init(GScanPlainBytes *); + +/* Supprime toutes les références externes. */ +static void g_scan_plain_bytes_dispose(GScanPlainBytes *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_plain_bytes_finalize(GScanPlainBytes *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Affiche un motif de recherche au format texte. */ +static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *, GScanContext *, int); + +/* Affiche un motif de recherche au format JSON. */ +static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *, GScanContext *, const sized_string_t *, unsigned int, int); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +G_DEFINE_TYPE(GScanPlainBytes, g_scan_plain_bytes, G_TYPE_BYTES_TOKEN); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des recherches de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GSearchPatternClass *pattern; /* Version de classe ancêtre */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_plain_bytes_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_plain_bytes_finalize; + + pattern = G_SEARCH_PATTERN_CLASS(klass); + + pattern->to_text = (output_pattern_to_text_fc)g_scan_plain_bytes_output_to_text; + pattern->to_json = (output_pattern_to_json_fc)g_scan_plain_bytes_output_to_json; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance à initialiser. * +* * +* Description : Initialise une instance de recherche de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_init(GScanPlainBytes *bytes) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes) +{ + G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->dispose(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes) +{ + G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->finalize(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : root = représentation du motif à recherche. * +* * +* Description : Construit un gestionnaire de recherche de texte brut. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *root) +{ + GSearchPattern *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PLAIN_BYTES, NULL); + + if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), root)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = encadrement de motif à initialiser pleinement. * +* root = représentation du motif à recherche. * +* * +* Description : Met en place un gestionnaire de recherche de texte brut. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, GScanTokenNode *root) +{ + bool result; /* Bilan à retourner */ + ScanPlainNodeFlags flags; /* Propriétés à interpréter */ + bool fullword; /* Cible de mots entiers ? */ + bool private; /* Vocation privée ? */ + + flags = g_scan_token_node_plain_get_flags(G_SCAN_TOKEN_NODE_PLAIN(root)); + + fullword = (flags & SPNF_FULLWORD); + private = (flags & SPNF_PRIVATE); + + result = g_bytes_token_create(G_BYTES_TOKEN(bytes), root, fullword, private); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *pattern, GScanContext *context, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_plain_bytes_parent_class)->to_text(G_SEARCH_PATTERN(pattern), context, fd); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_plain_bytes_parent_class)->to_json(G_SEARCH_PATTERN(pattern), context, padding, level, fd); + + /* TODO */ + +} diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h new file mode 100644 index 0000000..6ff48d7 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/plain.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - prototypes pour la recherche d'une chaîne de caractères brute + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H + + +#include <glib-object.h> + + +#include "node.h" +#include "../../pattern.h" + + + +#define G_TYPE_SCAN_PLAIN_BYTES g_scan_plain_bytes_get_type() +#define G_SCAN_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytes)) +#define G_IS_SCAN_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PLAIN_BYTES)) +#define G_SCAN_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytesClass)) +#define G_IS_SCAN_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PLAIN_BYTES)) +#define G_SCAN_PLAIN_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytesClass)) + + +/* Représentation d'une suite d'octets à retrouver (instance) */ +typedef struct _GScanPlainBytes GScanPlainBytes; + +/* Représentation d'une suite d'octets à retrouver (classe) */ +typedef struct _GScanPlainBytesClass GScanPlainBytesClass; + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +GType g_scan_plain_bytes_get_type(void); + +/* Construit un gestionnaire de recherche de texte brut. */ +GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H */ |