/* 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 .
*/
#include "plain.h"
#include
#include
#include "../token-int.h"
/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
/* Encadrement d'une recherche de texte brut (instance) */
struct _GPlainBytes
{
GStringToken parent; /* A laisser en premier */
uint8_t *raw; /* Octets recherchés */
size_t allocated; /* Taille allouée */
size_t used; /* Quantité d'octets utilisée */
phys_t atom_pos; /* Début de sélection atomique */
phys_t atom_len; /* Taille de ladite sélection */
phys_t atom_rem; /* Reste après l'atome */
patid_t pid; /* Identifiant de la bribe */
};
/* Encadrement d'une recherche de texte brut (classe) */
struct _GPlainBytesClass
{
GStringTokenClass parent; /* A laisser en premier */
};
/* Initialise la classe des recherches de texte brut. */
static void g_plain_bytes_class_init(GPlainBytesClass *klass);
/* Initialise une instance de recherche de texte brut. */
static void g_plain_bytes_init(GPlainBytes *);
/* Supprime toutes les références externes. */
static void g_plain_bytes_dispose(GPlainBytes *);
/* Procède à la libération totale de la mémoire. */
static void g_plain_bytes_finalize(GPlainBytes *);
/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
/* Inscrit la définition d'un motif dans un moteur de recherche. */
static bool g_plain_bytes_enroll(GPlainBytes *, GScanContext *, GEngineBackend *, size_t);
/* Transforme les correspondances locales en trouvailles. */
static void g_plain_bytes_check(const GPlainBytes *, GScanContext *, GBinContent *, pending_matches_t *);
/* ---------------------------------------------------------------------------------- */
/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
G_DEFINE_TYPE(GPlainBytes, g_plain_bytes, G_TYPE_STRING_TOKEN);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des recherches de texte brut. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_plain_bytes_class_init(GPlainBytesClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GSearchPatternClass *pattern; /* Version de classe ancêtre */
GStringTokenClass *token; /* Version de classe parente */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_plain_bytes_dispose;
object->finalize = (GObjectFinalizeFunc)g_plain_bytes_finalize;
pattern = G_SEARCH_PATTERN_CLASS(klass);
//pattern->prepare = (prepare_pattern_fc)g_plain_bytes_prepare;
//pattern->analyze = (analyze_pattern_fc)g_plain_bytes_analyze;
//pattern->count = (count_pattern_matchs_fc);
token = G_STRING_TOKEN_CLASS(klass);
token->enroll = (enroll_token_fc)g_plain_bytes_enroll;
token->check = (check_token_fc)g_plain_bytes_check;
}
/******************************************************************************
* *
* Paramètres : pattern = instance à initialiser. *
* *
* Description : Initialise une instance de recherche de texte brut. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_plain_bytes_init(GPlainBytes *bytes)
{
bytes->raw = NULL;
bytes->allocated = 0;
bytes->used = 0;
bytes->atom_pos = 0;
bytes->atom_len = 0;
bytes->atom_rem = 0;
bytes->pid = INVALID_PATTERN_ID;
}
/******************************************************************************
* *
* Paramètres : bytes = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_plain_bytes_dispose(GPlainBytes *bytes)
{
G_OBJECT_CLASS(g_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_plain_bytes_finalize(GPlainBytes *bytes)
{
if (bytes->raw != NULL)
free(bytes->raw);
G_OBJECT_CLASS(g_plain_bytes_parent_class)->finalize(G_OBJECT(bytes));
}
/******************************************************************************
* *
* Paramètres : text = texte brut à rechercher. *
* len = longueur de ce texte. *
* *
* Description : Construit un gestionnaire de recherche de texte brut. *
* *
* Retour : Mécanismes mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GSearchPattern *g_plain_bytes_new(const uint8_t *raw, size_t len)
{
GPlainBytes *result; /* Structure à retourner */
result = g_object_new(G_TYPE_PLAIN_BYTES, NULL);
result->raw = malloc(len);
result->allocated = len;
result->used = len;
memcpy(result->raw, raw, len);
return G_SEARCH_PATTERN(result);
}
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : bytes = 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). *
* *
* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
* *
* Retour : Bilan de l'opération à renvoyer. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_plain_bytes_enroll(GPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
{
bool result; /* Statut à retourner */
result = true;
bytes->atom_pos = 0;
if (bytes->used > maxsize) // Attention à la position de départ (à retrancher) !
{
bytes->atom_len = maxsize;
bytes->atom_rem = bytes->used - maxsize;
}
else
{
bytes->atom_len = bytes->used;
bytes->atom_rem = 0;
}
bytes->pid = g_engine_backend_enroll_plain_pattern(backend, context, bytes->raw, bytes->atom_len);
result = (bytes->pid != INVALID_PATTERN_ID);
return result;
}
/******************************************************************************
* *
* Paramètres : bytes = définition de la bribe à manipuler. *
* context = contexte de l'analyse à mener. *
* content = accès au contenu brut pour vérifications (optim.) *
* matches = suivi des correspondances à consolider. *
* *
* Description : Transforme les correspondances locales en trouvailles. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_plain_bytes_check(const GPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
{
bool initialized; /* Initialisation du suivi ? */
size_t count; /* Quantité de bribes trouvées */
const phys_t *found; /* Localisations des bribes */
size_t mindex; /* Indice d'élément à compléter*/
size_t i; /* Boucle de parcours */
phys_t start; /* Point de départ */
vmpa2t pos; /* Position dans les données */
const bin_t *ptr; /* Accès aux données brutes */
int ret; /* Bilan d'une comparaison */
initialized = are_pending_matches_initialized(matches);
found = g_scan_context_get_atom_matches(context, bytes->pid, &count);
mindex = 0;
for (i = 0; i < count; i++)
{
start = found[i] - bytes->atom_pos;
/* Recherche d'un point de départ attendu et conforme ? */
if (initialized)
if (!find_target_in_pending_matches(matches, start, &mindex))
continue;
init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
/* Validation du contenu avant l'atome */
if (bytes->atom_pos > 0)
{
ptr = g_binary_content_get_raw_access(content, &pos, bytes->atom_len);
ret = memcmp(bytes->raw + bytes->atom_pos, ptr, bytes->atom_len);
if (ret != 0) goto exclude_false_positive;
}
/* Validation du contenu après l'atome */
if (bytes->atom_rem > 0)
{
advance_vmpa(&pos, bytes->atom_len);
ptr = g_binary_content_get_raw_access(content, &pos, bytes->atom_rem);
ret = memcmp(bytes->raw + bytes->atom_pos + bytes->atom_len, ptr, bytes->atom_rem);
if (ret != 0) goto exclude_false_positive;
}
/* Mémorisation de la correspondance */
if (initialized)
extend_pending_matches(matches, mindex, bytes->used);
else
add_pending_matches(matches, start, bytes->used);
continue;
exclude_false_positive:
if (initialized)
remove_pending_matches(matches, mindex);
}
set_pending_matches_initialized(matches);
}