summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2023-09-12 04:43:02 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2023-09-12 04:45:25 (GMT)
commitfed4c10b9bb1c6f99440dba3839a1e7b56b40359 (patch)
treed544bde345c16a5eff19c0f9a074c09b366f7dbe /src/analysis
parent155c500b8933d2c7269215ea1d141d341de0a44f (diff)
Save current state with some ROST extra features.
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/scan/context.c6
-rw-r--r--src/analysis/scan/core.c34
-rw-r--r--src/analysis/scan/exprs/call.c2
-rw-r--r--src/analysis/scan/grammar.y288
-rw-r--r--src/analysis/scan/items/Makefile.am4
-rw-r--r--src/analysis/scan/items/console/log.c17
-rw-r--r--src/analysis/scan/items/math/Makefile.am13
-rw-r--r--src/analysis/scan/items/math/to_string.c381
-rw-r--r--src/analysis/scan/items/math/to_string.h58
-rw-r--r--src/analysis/scan/items/string/Makefile.am15
-rw-r--r--src/analysis/scan/items/string/lower.c270
-rw-r--r--src/analysis/scan/items/string/lower.h58
-rw-r--r--src/analysis/scan/items/string/to_int.c303
-rw-r--r--src/analysis/scan/items/string/to_int.h58
-rw-r--r--src/analysis/scan/items/string/upper.c270
-rw-r--r--src/analysis/scan/items/string/upper.h58
-rw-r--r--src/analysis/scan/matches/pending.c279
-rw-r--r--src/analysis/scan/matches/pending.h36
-rw-r--r--src/analysis/scan/patterns/token-int.h17
-rw-r--r--src/analysis/scan/patterns/token.c140
-rw-r--r--src/analysis/scan/patterns/token.h6
-rw-r--r--src/analysis/scan/patterns/tokens/Makefile.am1
-rw-r--r--src/analysis/scan/patterns/tokens/atom.c63
-rw-r--r--src/analysis/scan/patterns/tokens/atom.h5
-rw-r--r--src/analysis/scan/patterns/tokens/hex-int.h2
-rw-r--r--src/analysis/scan/patterns/tokens/hex.c210
-rw-r--r--src/analysis/scan/patterns/tokens/hex.h2
-rw-r--r--src/analysis/scan/patterns/tokens/node-int.h47
-rw-r--r--src/analysis/scan/patterns/tokens/node.c407
-rw-r--r--src/analysis/scan/patterns/tokens/node.h34
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/Makefile.am14
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any-int.h60
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.c425
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.h58
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice-int.h (renamed from src/analysis/scan/patterns/tokens/nodes/hub-int.h)21
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice.c486
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice.h61
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/hub.c150
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/hub.h55
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked-int.h63
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked.c814
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked.h72
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not-int.h57
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not.c364
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not.h59
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain-int.h4
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.c244
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.h16
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence-int.h58
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence.c360
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence.h61
-rw-r--r--src/analysis/scan/patterns/tokens/offset.c352
-rw-r--r--src/analysis/scan/patterns/tokens/offset.h101
-rw-r--r--src/analysis/scan/patterns/tokens/plain-int.h10
-rw-r--r--src/analysis/scan/patterns/tokens/plain.c257
-rw-r--r--src/analysis/scan/patterns/tokens/plain.h15
-rw-r--r--src/analysis/scan/rule.c7
-rw-r--r--src/analysis/scan/tokens.l334
58 files changed, 6690 insertions, 972 deletions
diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c
index 51fdd6b..9dd41cf 100644
--- a/src/analysis/scan/context.c
+++ b/src/analysis/scan/context.c
@@ -529,6 +529,8 @@ void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_
tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(phys_t));
}
+ printf("++ register pat=%llu @ %llu\n", (unsigned long long)id, (unsigned long long)offset); // REMME
+
tracker->matches[tracker->used++] = offset;
}
@@ -585,6 +587,8 @@ void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match
pattern = g_scan_match_get_source(match);
+ printf("// register match=%p for pattern=%p\n", pattern, match); // REMME
+
key.pattern = pattern;
found = bsearch((full_match_tracker_t *[]) { &key }, context->full_trackers, context->full_count,
@@ -637,7 +641,7 @@ const GScanMatch **g_scan_context_get_full_matches(const GScanContext *context,
if (found == NULL)
{
result = NULL;
- count = 0;
+ *count = 0;
}
else
diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c
index 3d4e529..0b2c1d5 100644
--- a/src/analysis/scan/core.c
+++ b/src/analysis/scan/core.c
@@ -37,6 +37,10 @@
# include "items/magic/mime-encoding.h"
# include "items/magic/mime-type.h"
#endif
+#include "items/math/to_string.h"
+#include "items/string/lower.h"
+#include "items/string/to_int.h"
+#include "items/string/upper.h"
#include "items/time/make.h"
#include "items/time/now.h"
#include "patterns/modifiers/hex.h"
@@ -280,6 +284,36 @@ bool populate_main_scan_namespace(GScanNamespace *space)
}
#endif
+ /* Math */
+
+ if (result)
+ {
+ ns = g_scan_namespace_new("math");
+ result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns));
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_math_to_string_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+
+ /* String */
+
+ if (result)
+ {
+ ns = g_scan_namespace_new("string");
+ result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns));
+
+ printf("g_scan_string_to_int_function_new(): %p\n", g_scan_string_to_int_function_new());
+
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_lower_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_to_int_function_new());
+ if (result) result = REGISTER_FUNC(ns, g_scan_string_upper_function_new());
+
+ g_object_unref(G_OBJECT(ns));
+
+ }
+
/* Time */
if (result)
diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c
index d9b2c13..f68159f 100644
--- a/src/analysis/scan/exprs/call.c
+++ b/src/analysis/scan/exprs/call.c
@@ -312,7 +312,7 @@ static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *exp
for (k = 0; k < i; k++)
{
- new_args[k] = expr->args[i];
+ new_args[k] = expr->args[k];
g_object_ref(G_OBJECT(new_args[k]));
}
diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y
index c0aa52d..64bcd5b 100644
--- a/src/analysis/scan/grammar.y
+++ b/src/analysis/scan/grammar.y
@@ -16,6 +16,8 @@ static int yyerror(GContentScanner *, yyscan_t, GScanRule **, sized_string_t *,
#define YY_TYPEDEF_YY_SCANNER_T
typedef void *yyscan_t;
+#include <assert.h>
+
#include "core.h"
#include "scanner.h"
#include "exprs/access.h"
@@ -34,7 +36,12 @@ typedef void *yyscan_t;
#include "patterns/modifiers/list.h"
#include "patterns/tokens/hex.h"
#include "patterns/tokens/plain.h"
+#include "patterns/tokens/nodes/any.h"
+#include "patterns/tokens/nodes/choice.h"
+#include "patterns/tokens/nodes/masked.h"
+#include "patterns/tokens/nodes/not.h"
#include "patterns/tokens/nodes/plain.h"
+#include "patterns/tokens/nodes/sequence.h"
#include "../../core/logs.h"
}
@@ -52,11 +59,11 @@ typedef void *yyscan_t;
sized_string_t *tmp_cstring; /* Série d'octets reconstituée */
- struct {
- bin_t byte; /* Valeur partielle recherchée */
- uint8_t mask; /* Masque associé */
- } semi_mask;
-
+ struct
+ {
+ sized_string_t *tmp_values; /* Série d'octets partiels */
+ sized_string_t *tmp_masks; /* Masques associés */
+ } masked;
GScanRule *rule; /* Nouvelle règle à intégrer */
@@ -66,7 +73,8 @@ typedef void *yyscan_t;
GScanTokenNode *node; /* Bribe de motif à intégrer */
GSearchPattern *pattern; /* Nouveau motif à considérer */
- GScanTokenModifier *modifier;
+ GScanTokenModifier *modifier; /* Modificateur pour texte */
+ ScanPlainNodeFlags str_flags; /* Fanions pour texte */
GScanExpression *expr; /* Expression de condition */
@@ -114,6 +122,11 @@ YY_DECL;
%token NAME
+%token NOCASE "nocase"
+%token FULLWORD "fullword"
+%token PRIVATE "private"
+
+
%token HEX_BYTES
%token FULL_MASK
%token SEMI_MASK
@@ -128,8 +141,8 @@ YY_DECL;
%token BRACE_IN BRACE_OUT ASSIGN COLON
-%token PLAIN_STRING
-%token MASKED_STRING
+%token PLAIN_TEXT
+%token ESCAPED_TEXT
%token TRUE_ "true"
%token FALSE_ "false"
@@ -204,25 +217,33 @@ YY_DECL;
%type <rule> rule
-%type <sized_cstring> PLAIN_STRING
-%type <pattern> MASKED_STRING
+%type <sized_cstring> PLAIN_TEXT
+%type <tmp_cstring> ESCAPED_TEXT
%type <tmp_cstring> HEX_BYTES
%type <unsigned_integer> FULL_MASK
-%type <semi_mask> SEMI_MASK
+%type <masked> SEMI_MASK
%type <tmp_cstring> REGEX_BYTES
+
+%type <pattern> str_pattern
+
%type <modifier> modifiers
%type <modifier> _modifiers
%type <modifier> chained_modifiers
%type <modifier> mod_stage
%type <modifier> modifier
+%type <str_flags> str_flags
+
+
%type <pattern> hex_pattern
%type <node> hex_tokens
%type <node> hex_token
+%type <node> hex_range
+%type <node> hex_choices
@@ -294,13 +315,21 @@ rules : /* empty */
//rule : RAW_RULE RULE_NAME { printf("RULE %s\n", $2); } RAW_BLOCK { printf("BLOCK: %s\n", $4); }
-external : "include" STRING
- {
- bool __status;
- __status = g_content_scanner_include_resource(scanner, $2.data);
- if (!__status)
- YYERROR;
- }
+ external : "include" PLAIN_TEXT
+ {
+ bool __status;
+ __status = g_content_scanner_include_resource(scanner, $2.data);
+ if (!__status)
+ YYERROR;
+ }
+ | "include" ESCAPED_TEXT
+ {
+ bool __status;
+ __status = g_content_scanner_include_resource(scanner, $2->data);
+ if (!__status)
+ YYERROR;
+ }
+ ;
rule : RAW_RULE RULE_NAME
@@ -320,11 +349,16 @@ rule : RAW_RULE RULE_NAME
strings : /* empty */
- | STRINGS COLON string_decls
+ | STRINGS COLON bytes_decls
;
- string_decls : string_decl
+ bytes_decls : str_pattern
+ {
+ if ($1 == NULL) YYERROR;
+ g_scan_rule_add_local_variable(*built_rule, $1);
+ g_object_unref(G_OBJECT($1));
+ }
| hex_pattern
{
if ($1 == NULL) YYERROR;
@@ -332,55 +366,51 @@ strings : /* empty */
g_object_unref(G_OBJECT($1));
}
| regex_pattern
- | string_decls string_decl
- | string_decls hex_pattern
+ | bytes_decls str_pattern
+ {
+ if ($2 == NULL) YYERROR;
+ g_scan_rule_add_local_variable(*built_rule, $2);
+ g_object_unref(G_OBJECT($2));
+ }
+ | bytes_decls hex_pattern
{
if ($2 == NULL) YYERROR;
g_scan_rule_add_local_variable(*built_rule, $2);
g_object_unref(G_OBJECT($2));
}
- | string_decls regex_pattern
+ | bytes_decls regex_pattern
;
-string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers
- {
- GSearchPattern *__pat;
- __pat = g_scan_plain_bytes_new(&$3, NULL, SPBF_NONE);
- g_search_pattern_set_name(__pat, $1.data, $1.len);
- g_scan_rule_add_local_variable(*built_rule, __pat);
- g_object_unref(G_OBJECT(__pat));
-
- /*
- string_token_t *__token;
- //printf("built plain %s\n", $3.cstring);
- GBytesPattern *__pat;
- __token = create_plain_string_token($3.cstring, $3.len);
- printf("token: %p\n", __token);
- __pat = g_bytes_pattern_new();
- g_bytes_pattern_append_string(__pat, $3.cstring, $3.len);
- g_scan_rule_add_local_variable(*built_rule, $1, G_SEARCH_PATTERN(__pat));
- g_object_unref(G_OBJECT(__pat));
- */
- }
- | BYTES_ID ASSIGN MASKED_STRING
- {
- printf("built %p\n", $3);
- /*
- GBytesPattern *__pat;
- __pat = g_bytes_pattern_new();
- g_search_pattern_set_name(__pat, $1.cstring, $1.len);
- g_bytes_pattern_append_string(__pat, "\xd9\x74\x24\xf4", 4);
- g_scan_rule_add_local_variable(*built_rule, G_SEARCH_PATTERN(__pat));
- */
- /*
- GSearchPattern *__pat;
- __pat = G_SEARCH_PATTERN($3);
- if (g_search_pattern_prepare(__pat))
- g_scan_rule_add_local_variable(*built_rule, $1, __pat);
- g_clear_object(built_pattern);
- */
- }
- ;
+
+/**
+ * Définition de motif en texte brut.
+ */
+
+ str_pattern : BYTES_ID ASSIGN PLAIN_TEXT modifiers str_flags
+ {
+ GScanTokenNode *node;
+
+ node = g_scan_token_node_plain_new(&$3, $4, $5);
+
+ $$ = g_scan_plain_bytes_new(node);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+ | BYTES_ID ASSIGN ESCAPED_TEXT modifiers str_flags
+ {
+ GScanTokenNode *node;
+
+ node = g_scan_token_node_plain_new($3, $4, $5);
+
+ $$ = g_scan_plain_bytes_new(node);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+ ;
/**
@@ -450,23 +480,70 @@ string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers
}
;
+
+/**
+ * Prise en charge des fanions pour texte.
+ */
+
+ str_flags : /* empty */
+ {
+ $$ = SPNF_NONE;
+ }
+ | str_flags "nocase"
+ {
+ $$ = $1 | SPNF_CASE_INSENSITIVE;
+ }
+ | str_flags "fullword"
+ {
+ $$ = $1 | SPNF_FULLWORD;
+ }
+ | str_flags "private"
+ {
+ $$ = $1 | SPNF_PRIVATE;
+ }
+ ;
+
+
/**
* Définition de motif en hexadécimal.
*/
hex_pattern : BYTES_ID ASSIGN hex_tokens
{
- $$ = g_scan_hex_bytes_new($3);
+ $$ = g_scan_hex_bytes_new($3, false);
+ g_search_pattern_set_name($$, $1.data, $1.len);
+ }
+ | BYTES_ID ASSIGN hex_tokens "private"
+ {
+ $$ = g_scan_hex_bytes_new($3, true);
g_search_pattern_set_name($$, $1.data, $1.len);
}
;
hex_tokens : hex_token
{
+ if ($1 == NULL) YYERROR;
+
$$ = $1;
+
}
| hex_tokens hex_token
{
+ if ($2 == NULL) YYERROR;
+
+ if (!G_IS_SCAN_TOKEN_NODE_SEQUENCE($1))
+ {
+ $$ = g_scan_token_node_sequence_new($1);
+ g_object_unref(G_OBJECT($1));
+ g_scan_token_node_sequence_add(G_SCAN_TOKEN_NODE_SEQUENCE($$), $2);
+ g_object_unref(G_OBJECT($2));
+ }
+ else
+ {
+ $$ = $1;
+ g_scan_token_node_sequence_add(G_SCAN_TOKEN_NODE_SEQUENCE($$), $2);
+ g_object_unref(G_OBJECT($2));
+ }
}
;
@@ -477,62 +554,115 @@ string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers
}
| FULL_MASK
{
- printf("mask len: %llu\n", $1);
+ phys_t min;
+ phys_t max;
+
+ min = $1;
+ max = $1;
+
+ $$ = g_scan_token_node_any_new(&min, &max);
+
}
| SEMI_MASK
{
- printf("semi mask: %hhx / %hhx \n", $1.byte, $1.mask);
+ size_t i;
+ masked_byte_t byte;
+
+ assert($1.tmp_values->len == $1.tmp_masks->len);
+
+ byte.value = $1.tmp_values->data[0];
+ byte.mask = $1.tmp_masks->data[0];
+
+ $$ = g_scan_token_node_masked_new(&byte);
+
+ for (i = 1; i < $1.tmp_values->len; i++)
+ {
+ byte.value = $1.tmp_values->data[i];
+ byte.mask = $1.tmp_masks->data[i];
+
+ g_scan_token_node_masked_add(G_SCAN_TOKEN_NODE_MASKED($$), &byte);
+
+ }
+
}
| hex_range
{
- printf("...range...\n");
+ $$ = $1;
}
| "~" hex_token
{
-
- printf("hex -- NOT --\n");
+ $$ = g_scan_token_node_not_new($2);
}
- | "(" hex_token "|" hex_token ")"
+ | "(" hex_choices ")"
{
-
- printf("hex -- OR --\n");
-
+ $$ = $2;
}
;
hex_range : "[" "-" "]"
{
-
- printf("got inf range\n");
-
+ $$ = g_scan_token_node_any_new(NULL, NULL);
}
| "[" UNSIGNED_INTEGER "]"
{
+ phys_t min;
+ phys_t max;
+
+ min = $2;
+ max = $2;
- printf("got range [%llu]\n", $2);
+ $$ = g_scan_token_node_any_new(&min, &max);
}
| "[" UNSIGNED_INTEGER "-" "]"
{
+ phys_t min;
+
+ min = $2;
- printf("got range [%llu -> ]\n", $2);
+ $$ = g_scan_token_node_any_new(&min, NULL);
}
| "[" "-" UNSIGNED_INTEGER "]"
{
+ phys_t max;
- printf("got range [ -> %llu]\n", $3);
+ max = $3;
+
+ $$ = g_scan_token_node_any_new(NULL, &max);
}
| "[" UNSIGNED_INTEGER "-" UNSIGNED_INTEGER "]"
{
+ phys_t min;
+ phys_t max;
+
+ min = $2;
+ max = $4;
- printf("got range [%llu -> %llu]\n", $2, $4);
+ $$ = g_scan_token_node_any_new(&min, &max);
}
;
+ hex_choices : hex_token "|" hex_token
+ {
+ $$ = g_scan_token_node_choice_new();
+ g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $1);
+ g_object_unref(G_OBJECT($1));
+ g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ | hex_choices "|" hex_token
+ {
+ $$ = $1;
+ g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $3);
+ g_object_unref(G_OBJECT($3));
+ }
+ ;
+
+
/**
* Définition de motif sous forme d'expression régulière
*/
diff --git a/src/analysis/scan/items/Makefile.am b/src/analysis/scan/items/Makefile.am
index ce39cad..89ae41e 100644
--- a/src/analysis/scan/items/Makefile.am
+++ b/src/analysis/scan/items/Makefile.am
@@ -20,6 +20,8 @@ libanalysisscanitems_la_SOURCES = \
libanalysisscanitems_la_LIBADD = \
console/libanalysisscanitemsconsole.la \
$(MAGIC_LIBADD) \
+ math/libanalysisscanitemsmath.la \
+ string/libanalysisscanitemsstring.la \
time/libanalysisscanitemstime.la
libanalysisscanitems_la_CFLAGS = $(LIBGOBJ_CFLAGS)
@@ -30,4 +32,4 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisscanitems_la_SOURCES:%c=)
-SUBDIRS = console $(MAGIC_SUBDIRS) time
+SUBDIRS = console $(MAGIC_SUBDIRS) math string time
diff --git a/src/analysis/scan/items/console/log.c b/src/analysis/scan/items/console/log.c
index f4031c7..02b6207 100644
--- a/src/analysis/scan/items/console/log.c
+++ b/src/analysis/scan/items/console/log.c
@@ -228,8 +228,8 @@ static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *item,
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours #1 */
- LiteralValueType vtype; /* Type de valeur portée */
GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
bool boolean; /* Valeur booléenne */
long long sinteger; /* Valeur entière signée */
unsigned long long uinteger; /* Valeur entière non signée */
@@ -275,13 +275,14 @@ static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *item,
case LVT_STRING:
result = g_scan_literal_expression_get_string_value(literal, &string);
- for (k = 0; k < string->len; k++)
- {
- if (isprint(string->data[k]))
- fprintf(stderr, "%c", string->data[k]);
- else
- fprintf(stderr, "\\x%02hhx", string->data[k]);
- }
+ if (result)
+ for (k = 0; k < string->len; k++)
+ {
+ if (isprint(string->data[k]))
+ fprintf(stderr, "%c", string->data[k]);
+ else
+ fprintf(stderr, "\\x%02hhx", string->data[k]);
+ }
break;
default:
diff --git a/src/analysis/scan/items/math/Makefile.am b/src/analysis/scan/items/math/Makefile.am
new file mode 100644
index 0000000..1f37c72
--- /dev/null
+++ b/src/analysis/scan/items/math/Makefile.am
@@ -0,0 +1,13 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemsmath.la
+
+
+libanalysisscanitemsmath_la_SOURCES = \
+ to_string.h to_string.c
+
+libanalysisscanitemsmath_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsmath_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/math/to_string.c b/src/analysis/scan/items/math/to_string.c
new file mode 100644
index 0000000..4bb8363
--- /dev/null
+++ b/src/analysis/scan/items/math/to_string.c
@@ -0,0 +1,381 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_string.c - conversion d'une valeur entière en chaîne
+ *
+ * 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 "to_string.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de texte en entier. */
+static void g_scan_math_to_string_function_class_init(GScanMathToStringFunctionClass *);
+
+/* Initialise une instance de conversion de texte en entier. */
+static void g_scan_math_to_string_function_init(GScanMathToStringFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_math_to_string_function_dispose(GScanMathToStringFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_math_to_string_function_finalize(GScanMathToStringFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_math_to_string_function_get_name(const GScanMathToStringFunction *);
+
+/* Réalise la conversion d'une valeur en texte. */
+static void convert_integer_to_string(unsigned long long, unsigned long long, char **);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_math_to_string_function_run_call(GScanMathToStringFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion d'entier en texte. */
+G_DEFINE_TYPE(GScanMathToStringFunction, g_scan_math_to_string_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conversions de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_class_init(GScanMathToStringFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_math_to_string_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_math_to_string_function_finalize;
+
+ registered = G_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_math_to_string_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_math_to_string_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de conversion de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_init(GScanMathToStringFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_dispose(GScanMathToStringFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_math_to_string_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_finalize(GScanMathToStringFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_math_to_string_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une fonction de conversion de valeur entière en texte. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRegisteredItem *g_scan_math_to_string_function_new(void)
+{
+ GRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_math_to_string_function_get_name(const GScanMathToStringFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("to_string");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : val = valeur entière à traiter. *
+* base = base à considérer. *
+* data = tête d'écriture à faire évoluer. [OUT] *
+* *
+* Description : Réalise la conversion d'une valeur en texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void convert_integer_to_string(unsigned long long val, unsigned long long base, char **data)
+{
+ static const char digits[16] = "0123456789abcdef";
+
+ if (val < base)
+ *((*data)++) = digits[val];
+
+ else
+ {
+ convert_integer_to_string(val / base, base, data);
+
+ *((*data)++) = digits[val % base];
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_math_to_string_function_run_call(GScanMathToStringFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ long long sval; /* Valeur signée obtenue */
+ unsigned long long uval; /* Valeur non signée obtenue */
+ bool negative; /* Besoin de signe en préfixe ?*/
+ unsigned long long base; /* Base de conversion */
+ char *data; /* Chaîne "C" à constituer */
+ char *iter; /* Tête d'écriture */
+ sized_string_t string; /* Chaîne finale complète */
+
+ /* Validation des arguments */
+
+ result = (count == 1 || count == 2);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_SIGNED_INTEGER || vtype == LVT_UNSIGNED_INTEGER);
+ if (!result) goto exit;
+
+ if (vtype == LVT_SIGNED_INTEGER)
+ {
+ result = g_scan_literal_expression_get_signed_integer_value(literal, &sval);
+ if (!result) goto exit;
+
+ assert(sval < 0);
+
+ negative = (sval < 0);
+
+ if (negative)
+ uval = -sval;
+
+ }
+ else
+ {
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &uval);
+ if (!result) goto exit;
+ }
+
+ if (count == 1)
+ base = 10;
+
+ else
+ {
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[1]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[1]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_UNSIGNED_INTEGER);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &base);
+ if (!result) goto exit;
+
+ result = (base == 2 || base == 8 || base == 10 || base == 16);
+ if (!result) goto exit;
+
+ }
+
+ /* Réalisation de l'opération attendue */
+
+ data = malloc((1 + 2 + 64 * 8 + 1) * sizeof(char));
+ iter = data;
+
+ if (negative)
+ *(iter++) = '-';
+
+ switch (base)
+ {
+ case 2:
+ *(iter++) = '0';
+ *(iter++) = 'b';
+ break;
+
+ case 8:
+ *(iter++) = '0';
+ break;
+
+ case 10:
+ break;
+
+ case 16:
+ *(iter++) = '0';
+ *(iter++) = 'x';
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ convert_integer_to_string(uval, base, &iter);
+
+ string.data = data;
+ string.len = iter - data;
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string));
+
+ free(data);
+
+ result = true;
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/math/to_string.h b/src/analysis/scan/items/math/to_string.h
new file mode 100644
index 0000000..19f0020
--- /dev/null
+++ b/src/analysis/scan/items/math/to_string.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_string.h - prototypes pour la conversion d'une valeur entière en chaîne
+ *
+ * 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_ITEMS_MATH_TO_STRING_H
+#define _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_MATH_TO_STRING_FUNCTION g_scan_math_to_string_function_get_type()
+#define G_SCAN_MATH_TO_STRING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunction))
+#define G_IS_SCAN_MATH_TO_STRING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION))
+#define G_SCAN_MATH_TO_STRING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunctionClass))
+#define G_IS_SCAN_MATH_TO_STRING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION))
+#define G_SCAN_MATH_TO_STRING_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunctionClass))
+
+
+/* Conversion d'une valeur entière en valeur textuelle (instance) */
+typedef GRegisteredItem GScanMathToStringFunction;
+
+/* Conversion d'une valeur entière en valeur textuelle (classe) */
+typedef GRegisteredItemClass GScanMathToStringFunctionClass;
+
+
+/* Indique le type défini pour une conversion d'entier en texte. */
+GType g_scan_math_to_string_function_get_type(void);
+
+/* Crée une fonction de conversion de valeur entière en texte. */
+GRegisteredItem *g_scan_math_to_string_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H */
diff --git a/src/analysis/scan/items/string/Makefile.am b/src/analysis/scan/items/string/Makefile.am
new file mode 100644
index 0000000..c9ce6a3
--- /dev/null
+++ b/src/analysis/scan/items/string/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_LTLIBRARIES = libanalysisscanitemsstring.la
+
+
+libanalysisscanitemsstring_la_SOURCES = \
+ lower.h lower.c \
+ to_int.h to_int.c \
+ upper.h upper.c
+
+libanalysisscanitemsstring_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsstring_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/string/lower.c b/src/analysis/scan/items/string/lower.c
new file mode 100644
index 0000000..be8b133
--- /dev/null
+++ b/src/analysis/scan/items/string/lower.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.c - bascule de lettres en minuscules
+ *
+ * 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 "lower.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de lettres en minuscules. */
+static void g_scan_string_lower_function_class_init(GScanStringLowerFunctionClass *);
+
+/* Initialise une instance de bascule de lettres en minuscules. */
+static void g_scan_string_lower_function_init(GScanStringLowerFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_lower_function_dispose(GScanStringLowerFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_lower_function_finalize(GScanStringLowerFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_lower_function_get_name(const GScanStringLowerFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_lower_function_run_call(GScanStringLowerFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+G_DEFINE_TYPE(GScanStringLowerFunction, g_scan_string_lower_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bascules de lettres en minuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_class_init(GScanStringLowerFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_lower_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_lower_function_finalize;
+
+ registered = G_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_lower_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_lower_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de bascule de lettres en minuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_init(GScanStringLowerFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_dispose(GScanStringLowerFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_lower_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_lower_function_finalize(GScanStringLowerFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_lower_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de bascule de lettres en minuscules. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRegisteredItem *g_scan_string_lower_function_new(void)
+{
+ GRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_LOWER_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_lower_function_get_name(const GScanStringLowerFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("lower");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_lower_function_run_call(GScanStringLowerFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Description du chaîne */
+ sized_string_t new; /* Description transformée */
+ size_t i; /* Boucle de parcours */
+
+ /* Validation des arguments */
+
+ result = (count == 1);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ /* Réalisation de l'opération attendue */
+
+ new.data = malloc(string->len);
+ new.len = string->len;
+
+ for (i = 0; i < string->len; i++)
+ new.data[i] = tolower(string->data[i]);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+ exit_szstr(&new);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/lower.h b/src/analysis/scan/items/string/lower.h
new file mode 100644
index 0000000..f844a65
--- /dev/null
+++ b/src/analysis/scan/items/string/lower.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.h - prototypes pour la bascule de lettres en minuscules
+ *
+ * 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_ITEMS_STRING_LOWER_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_LOWER_FUNCTION g_scan_string_lower_function_get_type()
+#define G_SCAN_STRING_LOWER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunction))
+#define G_IS_SCAN_STRING_LOWER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION))
+#define G_SCAN_STRING_LOWER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunctionClass))
+#define G_IS_SCAN_STRING_LOWER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_LOWER_FUNCTION))
+#define G_SCAN_STRING_LOWER_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunctionClass))
+
+
+/* Bascule d'une suite de caractères en minuscules (instance) */
+typedef GRegisteredItem GScanStringLowerFunction;
+
+/* Bascule d'une suite de caractères en minuscules (classe) */
+typedef GRegisteredItemClass GScanStringLowerFunctionClass;
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+GType g_scan_string_lower_function_get_type(void);
+
+/* Constitue une fonction de bascule de lettres en minuscules. */
+GRegisteredItem *g_scan_string_lower_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H */
diff --git a/src/analysis/scan/items/string/to_int.c b/src/analysis/scan/items/string/to_int.c
new file mode 100644
index 0000000..8031d4d
--- /dev/null
+++ b/src/analysis/scan/items/string/to_int.c
@@ -0,0 +1,303 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_int.c - conversion d'une chaîne en valeur entière
+ *
+ * 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 "to_int.h"
+
+
+#include <stdlib.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de texte en entier. */
+static void g_scan_string_to_int_function_class_init(GScanStringToIntFunctionClass *);
+
+/* Initialise une instance de conversion de texte en entier. */
+static void g_scan_string_to_int_function_init(GScanStringToIntFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_to_int_function_dispose(GScanStringToIntFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_to_int_function_finalize(GScanStringToIntFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_to_int_function_get_name(const GScanStringToIntFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_to_int_function_run_call(GScanStringToIntFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion de texte en entier. */
+G_DEFINE_TYPE(GScanStringToIntFunction, g_scan_string_to_int_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conversions de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_class_init(GScanStringToIntFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_to_int_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_to_int_function_finalize;
+
+ registered = G_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_to_int_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_to_int_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de conversion de texte en entier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_init(GScanStringToIntFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_dispose(GScanStringToIntFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_to_int_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_finalize(GScanStringToIntFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_to_int_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une fonction de conversion de texte en valeur entière. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRegisteredItem *g_scan_string_to_int_function_new(void)
+{
+ GRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_TO_INT_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_to_int_function_get_name(const GScanStringToIntFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("to_int");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_to_int_function_run_call(GScanStringToIntFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Chaîne à convertir */
+ unsigned long long base; /* Base de conversion */
+ char *data; /* Chaîne "C" à considérer */
+ long long sval; /* Valeur signée obtenue */
+ unsigned long long uval; /* Valeur non signée obtenue */
+
+ /* Validation des arguments */
+
+ result = (count == 1 || count == 2);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ if (string->len == 0) goto exit;
+
+ if (count == 1)
+ base = 0;
+
+ else
+ {
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[1]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[1]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_UNSIGNED_INTEGER);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_unsigned_integer_value(literal, &base);
+ if (!result) goto exit;
+
+ }
+
+ /* Réalisation de l'opération attendue */
+
+ data = strndup(string->data, string->len);
+
+ if (string->data[0] == '-')
+ {
+ sval = strtoll(data, NULL, base);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &sval));
+
+ }
+ else
+ {
+ uval = strtoll(data, NULL, base);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &uval));
+
+ }
+
+ free(data);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/to_int.h b/src/analysis/scan/items/string/to_int.h
new file mode 100644
index 0000000..143da44
--- /dev/null
+++ b/src/analysis/scan/items/string/to_int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_int.h - prototypes pour la conversion d'une chaîne en valeur entière
+ *
+ * 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_ITEMS_STRING_TO_INT_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_TO_INT_FUNCTION g_scan_string_to_int_function_get_type()
+#define G_SCAN_STRING_TO_INT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunction))
+#define G_IS_SCAN_STRING_TO_INT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION))
+#define G_SCAN_STRING_TO_INT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunctionClass))
+#define G_IS_SCAN_STRING_TO_INT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_TO_INT_FUNCTION))
+#define G_SCAN_STRING_TO_INT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunctionClass))
+
+
+/* Conversion d'une valeur textuelle en valeur entière (instance) */
+typedef GRegisteredItem GScanStringToIntFunction;
+
+/* Conversion d'une valeur textuelle en valeur entière (classe) */
+typedef GRegisteredItemClass GScanStringToIntFunctionClass;
+
+
+/* Indique le type défini pour une conversion de texte en entier. */
+GType g_scan_string_to_int_function_get_type(void);
+
+/* Crée une fonction de conversion de texte en valeur entière. */
+GRegisteredItem *g_scan_string_to_int_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H */
diff --git a/src/analysis/scan/items/string/upper.c b/src/analysis/scan/items/string/upper.c
new file mode 100644
index 0000000..2ddd0dc
--- /dev/null
+++ b/src/analysis/scan/items/string/upper.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.c - bascule de lettres en majuscules
+ *
+ * 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 "upper.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de lettres en majuscules. */
+static void g_scan_string_upper_function_class_init(GScanStringUpperFunctionClass *);
+
+/* Initialise une instance de bascule de lettres en majuscules. */
+static void g_scan_string_upper_function_init(GScanStringUpperFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_upper_function_dispose(GScanStringUpperFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_upper_function_finalize(GScanStringUpperFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_upper_function_get_name(const GScanStringUpperFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_upper_function_run_call(GScanStringUpperFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+G_DEFINE_TYPE(GScanStringUpperFunction, g_scan_string_upper_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bascules de lettres en majuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_class_init(GScanStringUpperFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_upper_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_string_upper_function_finalize;
+
+ registered = G_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_string_upper_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_string_upper_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de bascule de lettres en majuscules. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_init(GScanStringUpperFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_dispose(GScanStringUpperFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_upper_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_string_upper_function_finalize(GScanStringUpperFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_string_upper_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de bascule de lettres en majuscules. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRegisteredItem *g_scan_string_upper_function_new(void)
+{
+ GRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_STRING_UPPER_FUNCTION, NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* *
+* Description : Indique le nom associé à une expression d'évaluation. *
+* *
+* Retour : Désignation humaine de l'expression d'évaluation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_string_upper_function_get_name(const GScanStringUpperFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("upper");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément d'appel à consulter. *
+* args = liste d'éventuels arguments fournis. *
+* count = taille de cette liste. *
+* ctx = contexte de suivi de l'analyse courante. *
+* scope = portée courante des variables locales. *
+* out = zone d'enregistrement de la résolution opérée. [OUT] *
+* *
+* Description : Réduit une expression à une forme plus simple. *
+* *
+* Retour : Réduction correspondante, expression déjà réduite, ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_string_upper_function_run_call(GScanStringUpperFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ GScanLiteralExpression *literal; /* Version plus accessible */
+ LiteralValueType vtype; /* Type de valeur portée */
+ const sized_string_t *string; /* Description du chaîne */
+ sized_string_t new; /* Description transformée */
+ size_t i; /* Boucle de parcours */
+
+ /* Validation des arguments */
+
+ result = (count == 1);
+ if (!result) goto exit;
+
+ result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+ if (!result) goto exit;
+
+ literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+ vtype = g_scan_literal_expression_get_value_type(literal);
+
+ result = (vtype == LVT_STRING);
+ if (!result) goto exit;
+
+ result = g_scan_literal_expression_get_string_value(literal, &string);
+ if (!result) goto exit;
+
+ /* Réalisation de l'opération attendue */
+
+ new.data = malloc(string->len);
+ new.len = string->len;
+
+ for (i = 0; i < string->len; i++)
+ new.data[i] = toupper(string->data[i]);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+ exit_szstr(&new);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/string/upper.h b/src/analysis/scan/items/string/upper.h
new file mode 100644
index 0000000..4f6e4bc
--- /dev/null
+++ b/src/analysis/scan/items/string/upper.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.h - prototypes pour la bascule de lettres en majuscules
+ *
+ * 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_ITEMS_STRING_UPPER_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_UPPER_FUNCTION g_scan_string_upper_function_get_type()
+#define G_SCAN_STRING_UPPER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunction))
+#define G_IS_SCAN_STRING_UPPER_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION))
+#define G_SCAN_STRING_UPPER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunctionClass))
+#define G_IS_SCAN_STRING_UPPER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_UPPER_FUNCTION))
+#define G_SCAN_STRING_UPPER_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunctionClass))
+
+
+/* Bascule d'une suite de caractères en majuscules (instance) */
+typedef GRegisteredItem GScanStringUpperFunction;
+
+/* Bascule d'une suite de caractères en majuscules (classe) */
+typedef GRegisteredItemClass GScanStringUpperFunctionClass;
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+GType g_scan_string_upper_function_get_type(void);
+
+/* Constitue une fonction de bascule de lettres en majuscules. */
+GRegisteredItem *g_scan_string_upper_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H */
diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c
index 9d1037d..03cf3f2 100644
--- a/src/analysis/scan/matches/pending.c
+++ b/src/analysis/scan/matches/pending.c
@@ -24,18 +24,80 @@
#include "pending.h"
-#include <assert.h>
#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
+#include "../../../common/sort.h"
+
+
+
+/* ------------------------- MEMORISATION D'UNE ZONE BORNEE ------------------------- */
+
+
+/* Compare deux couvertures bornées de correspondances. */
+static int compare_match_area(const match_area_t *, const match_area_t *);
+
+
+
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
+
+
#define PENDING_ALLOC_SIZE 10
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MEMORISATION D'UNE ZONE BORNEE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : a = pointeur vers la première zone à analyser. *
+* b = pointeur vers la seconde zone à analyser. *
+* *
+* Description : Compare deux couvertures bornées de correspondances. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_match_area(const match_area_t *a, const match_area_t *b)
+{
+ int result; /* Bilan à renvoyer */
+
+ result = sort_unsigned_long_long(a->start, b->start);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->end, b->end);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->ttl, b->ttl);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION DE CORRESPONDANCES ETABLIES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : matches = suivi de correspondances à initialiser. *
+* start = première position du contenu (souvent 0). *
+* end = position de fin du contenu. *
* *
* Description : Initialise une structure de consolidation de correspondances.*
* *
@@ -45,14 +107,84 @@
* *
******************************************************************************/
-void init_pending_matches(pending_matches_t *matches)
+void init_pending_matches(pending_matches_t *matches, const phys_t *start, const phys_t *end)
{
+ matches->content_start = *start;
+ matches->content_end = *end;
+
matches->areas = NULL;
matches->allocated = 0;
matches->used = 0;
matches->initialized = false;
+ matches->abort = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de correspondances à initialiser. [OUT] *
+* src = suivi de correspondances à copier. *
+* *
+* Description : Copie une structure de consolidation de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void copy_pending_matches(pending_matches_t *dest, const pending_matches_t *src)
+{
+ dest->content_start = src->content_start;
+ dest->content_end = src->content_end;
+
+ dest->areas = malloc(src->used * sizeof(match_area_t));
+ dest->allocated = src->used;
+ dest->used = src->used;
+
+ memcpy(dest->areas, src->areas, src->used * sizeof(match_area_t));
+
+ dest->initialized = src->initialized;
+
+ dest->abort = src->abort;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de correspondances à initialiser. [OUT] *
+* src = suivi de correspondances à copier. *
+* *
+* Description : Fusionne une structure de consolidation avec une autre. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void merge_pending_matches(pending_matches_t *dest, const pending_matches_t *src)
+{
+ if ((dest->used + src->used) > dest->allocated)
+ {
+ dest->allocated += src->used;
+
+ dest->areas = realloc(dest->areas, dest->allocated * sizeof(match_area_t));
+
+ }
+
+ memcpy(&dest->areas[dest->used], src->areas, src->used * sizeof(match_area_t));
+
+ dest->used += src->used;
+
+ dest->initialized |= src->initialized;
+
+ dest->abort |= src->abort;
+
}
@@ -112,11 +244,11 @@ size_t count_pending_matches(const pending_matches_t *matches)
* *
******************************************************************************/
-const match_area_t *get_all_pending_matches(const pending_matches_t *matches, size_t *count)
+match_area_t * const *get_all_pending_matches(const pending_matches_t *matches, size_t *count)
{
- match_area_t *result; /* Série à renvoyer */
+ match_area_t * const *result; /* Série à renvoyer */
- result = matches->areas;
+ result = &matches->areas;
*count = matches->used;
@@ -156,8 +288,15 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
area->start = start;
area->end = start + length;
+ assert(matches->content_start <= area->start);
+ assert(area->end <= matches->content_end);
+
area->ttl = 1;
+ printf("[i] new match: from %llx to %llx\n",
+ (unsigned long long)area->start,
+ (unsigned long long)area->end);
+
}
@@ -165,7 +304,7 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
* *
* Paramètres : matches = suivi de correspondances à compléter. *
* target = indice de la zone de correspondance concernée. *
-* length = taille de la zone couverte supplémentaire. *
+* start = nouvelle position initiale de la zone couverte. *
* *
* Description : Etend une zone couverte dans le suivi des correspondances. *
* *
@@ -175,17 +314,19 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
* *
******************************************************************************/
-void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
+void extend_pending_match_beginning(pending_matches_t *matches, size_t target, phys_t start)
{
match_area_t *area; /* Zone à actualiser */
assert(target < matches->used);
- area = &matches->areas[matches->used++];
+ area = &matches->areas[target];
if (area->ttl == 0)
{
- area->end = end;
+ assert(matches->content_start <= start);
+
+ area->start = start;
area->ttl = 1;
@@ -194,7 +335,7 @@ void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
{
assert(area->ttl == 1);
- add_pending_match(matches, area->start, end - area->start);
+ add_pending_match(matches, start, area->end - start);
}
@@ -203,11 +344,11 @@ void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
/******************************************************************************
* *
-* Paramètres : matches = suivi de correspondances à consulter. *
+* Paramètres : matches = suivi de correspondances à compléter. *
* target = indice de la zone de correspondance concernée. *
-* pos = position à tester. *
+* length = taille de la zone couverte supplémentaire. *
* *
-* Description : Détermine si une correspondance se termine à une position. *
+* Description : Etend une zone couverte dans le suivi des correspondances. *
* *
* Retour : - *
* *
@@ -215,50 +356,40 @@ void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
* *
******************************************************************************/
-bool has_pending_match_ending_at(const pending_matches_t *matches, size_t target, phys_t pos)
+void extend_pending_match_ending(pending_matches_t *matches, size_t target, phys_t end)
{
- bool result; /* Statut à retourner */
- match_area_t *area; /* Couverture visée */
+ match_area_t *area; /* Zone à actualiser */
assert(target < matches->used);
area = &matches->areas[target];
- result = (area->end == pos);
-
- return result;
-
-}
+ if (area->ttl == 0)
+ {
+ assert(end <= matches->content_end);
+ printf(" -- extend same (%llu - %llu) -> new end: %llu\n",
+ (unsigned long long)area->start,
+ (unsigned long long)area->end,
+ (unsigned long long)end);
-/******************************************************************************
-* *
-* Paramètres : matches = suivi de correspondances à consulter. *
-* target = indice de la zone de correspondance concernée. *
-* pos = position à tester. *
-* min = borne inférieure de l'espace à considérer. *
-* max = borne supérieure de l'espace à considérer. *
-* *
-* Description : Détermine si une correspondance se situe dans une plage. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ area->end = end;
-bool has_pending_match_ending_between(const pending_matches_t *matches, size_t target, phys_t pos, phys_t min, phys_t max)
-{
- bool result; /* Statut à retourner */
- match_area_t *area; /* Couverture visée */
+ area->ttl = 1;
- assert(target < matches->used);
+ }
+ else
+ {
+ assert(area->ttl == 1);
- area = &matches->areas[target];
+ printf(" -- extend (%llu - %llu) -> new end: %llu\n",
+ (unsigned long long)area->start,
+ (unsigned long long)area->end,
+ (unsigned long long)end);
- result = ((area->end + min) <= pos && pos <= (area->end + max));
+ add_pending_match(matches, area->start, end - area->start);
- return result;
+ }
}
@@ -279,6 +410,8 @@ void reset_pending_matches_ttl(pending_matches_t *matches)
{
size_t i; /* Boucle de parcours */
+ assert(matches->initialized);
+
for (i = 0; i < matches->used; i++)
matches->areas[i].ttl = 0;
@@ -305,6 +438,8 @@ void purge_pending_matches(pending_matches_t *matches)
size_t del_count; /* Nombre d'éléments à effacer */
size_t i; /* Boucle de parcours */
+ assert(matches->initialized);
+
/**
* Note : le code original était le suivant :
*
@@ -378,4 +513,60 @@ void purge_pending_matches(pending_matches_t *matches)
}
+ /* Bilan */
+
+ matches->abort = (matches->used == 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à finaliser. *
+* *
+* Description : Trie les correspondances et retire tous les doublons. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void sort_and_filter_pending_matches(pending_matches_t *matches)
+{
+ match_area_t *last; /* Dernière zone conservée */
+ size_t i; /* Boucle de parcours */
+ match_area_t *cur; /* Zone courante dans l'analyse*/
+
+ if (matches->used > 0)
+ {
+ qsort(matches->areas, matches->used, sizeof(match_area_t), (__compar_fn_t)compare_match_area);
+
+ last = &matches->areas[0];
+
+ for (i = 1; i < matches->used; i++)
+ {
+ cur = &matches->areas[i];
+
+ if (last->start != cur->start || last->end != cur->end)
+ {
+ if ((cur - last) > 1)
+ {
+ memmove(last + 1, cur, (matches->used - i) * sizeof(match_area_t));
+ matches->used -= (cur - last + 1);
+ }
+
+ last = cur;
+
+ }
+
+ }
+
+ cur = &matches->areas[matches->used - 1];
+
+ if (last != cur)
+ matches->used = last - matches->areas + 1;
+
+ }
+
}
diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h
index 0a1fe5c..6df01c9 100644
--- a/src/analysis/scan/matches/pending.h
+++ b/src/analysis/scan/matches/pending.h
@@ -25,6 +25,7 @@
#define _ANALYSIS_SCAN_MATCHES_PENDING_H
+#include <assert.h>
#include <stdbool.h>
@@ -45,17 +46,28 @@ typedef struct _match_area_t
/* Suivi de correspondances */
typedef struct _pending_matches_t
{
+ phys_t content_start; /* Point de début du contenu */
+ phys_t content_end; /* Point de fin du contenu */
+
match_area_t *areas; /* Zones couvertes */
size_t allocated; /* Nombre d'allocations */
size_t used; /* Nombre de zones */
bool initialized; /* Etat du suivi */
+ bool abort; /* Inutilité d'une poursuite */
+
} pending_matches_t;
/* Initialise une structure de consolidation de correspondances. */
-void init_pending_matches(pending_matches_t *);
+void init_pending_matches(pending_matches_t *, const phys_t *, const phys_t *);
+
+/* Copie une structure de consolidation de correspondances. */
+void copy_pending_matches(pending_matches_t *, const pending_matches_t *);
+
+/* Fusionner une structure de consolidation avec une autre. */
+void merge_pending_matches(pending_matches_t *, const pending_matches_t *);
/* Libère la mémoire utilisée par une consolidation. */
void exit_pending_matches(pending_matches_t *);
@@ -69,26 +81,34 @@ void exit_pending_matches(pending_matches_t *);
size_t count_pending_matches(const pending_matches_t *);
/* Fournit la liste des correspondances établies à présent. */
-const match_area_t *get_all_pending_matches(const pending_matches_t *, size_t *);
+match_area_t * const *get_all_pending_matches(const pending_matches_t *, size_t *);
/* Ajoute au suivi la définition d'une nouvelle correspondance. */
void add_pending_match(pending_matches_t *, phys_t, phys_t);
/* Etend une zone couverte dans le suivi des correspondances. */
-void extend_pending_match(pending_matches_t *, size_t, phys_t);
+void extend_pending_match_beginning(pending_matches_t *, size_t, phys_t);
-/* Détermine si une correspondance se situe dans une plage. */
-bool has_pending_match_ending_between(const pending_matches_t *, size_t, phys_t, phys_t, phys_t);
-
-/* Détermine si une correspondance se termine à une position. */
-bool has_pending_match_ending_at(const pending_matches_t *, size_t, phys_t);
+/* Etend une zone couverte dans le suivi des correspondances. */
+void extend_pending_match_ending(pending_matches_t *, size_t, phys_t);
/* Réinitialisation à 0 tous les TTL de correspondances. */
void reset_pending_matches_ttl(pending_matches_t *);
+#define keep_pending_match(p) \
+ do \
+ { \
+ assert(p->ttl == 0); \
+ p->ttl = 1; \
+ } \
+ while (0);
+
/* Retire toutes les correspondances sans issue pour l'analyse. */
void purge_pending_matches(pending_matches_t *);
+/* Trie les correspondances et retire tous les doublons. */
+void sort_and_filter_pending_matches(pending_matches_t *);
+
#endif /* _ANALYSIS_SCAN_MATCHES_PENDING_H */
diff --git a/src/analysis/scan/patterns/token-int.h b/src/analysis/scan/patterns/token-int.h
index 294a3b1..f1d63f0 100644
--- a/src/analysis/scan/patterns/token-int.h
+++ b/src/analysis/scan/patterns/token-int.h
@@ -32,19 +32,17 @@
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-typedef bool (* enroll_token_fc) (GStringToken *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_token_fc) (const GStringToken *, GScanContext *, GBinContent *, pending_matches_t *);
-
-
/* Encadrement d'une bribe de recherche textuelle (instance) */
struct _GStringToken
{
GSearchPattern parent; /* A laisser en premier */
GScanTokenNode *root; /* Motif à rechercher */
+ size_t slow; /* Surcoût du motif */
+ bool need_backward; /* Besoin d'une seconde passe */
+
+ bool fullword; /* Cible de mots entiers ? */
+ bool private; /* Vocation privée ? */
};
@@ -53,14 +51,11 @@ struct _GStringTokenClass
{
GSearchPatternClass parent; /* A laisser en premier */
- enroll_token_fc enroll; /* Inscription d'un motif */
- check_token_fc check; /* Conversion en trouvailles */
-
};
/* Met en place un gestionnaire de recherche de binaire. */
-bool g_string_token_create(GStringToken *, GScanTokenNode *);
+bool g_string_token_create(GStringToken *, GScanTokenNode *, bool, bool);
diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c
index cc2d87a..1b2ee8a 100644
--- a/src/analysis/scan/patterns/token.c
+++ b/src/analysis/scan/patterns/token.c
@@ -25,6 +25,7 @@
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
@@ -116,6 +117,11 @@ static void g_string_token_class_init(GStringTokenClass *klass)
static void g_string_token_init(GStringToken *token)
{
token->root = NULL;
+ token->slow = 0;
+ token->need_backward = false;
+
+ token->fullword = false;
+ token->private = false;
}
@@ -160,8 +166,10 @@ static void g_string_token_finalize(GStringToken *token)
/******************************************************************************
* *
-* Paramètres : token = encadrement de motif à initialiser pleinement. *
-* root = représentation du motif à recherche. *
+* Paramètres : token = encadrement de motif à initialiser pleinement. *
+* root = représentation du motif à recherche. *
+* fullword = limite les correspondances à des mots entiers. *
+* private = donne une vocation privée au motif de recherche. *
* *
* Description : Met en place un gestionnaire de recherche de binaire. *
* *
@@ -171,7 +179,7 @@ static void g_string_token_finalize(GStringToken *token)
* *
******************************************************************************/
-bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
+bool g_string_token_create(GStringToken *token, GScanTokenNode *root, bool fullword, bool private)
{
bool result; /* Bilan à retourner */
@@ -180,6 +188,9 @@ bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
token->root = root;
g_object_ref(G_OBJECT(root));
+ token->fullword = fullword;
+ token->private = private;
+
return result;
}
@@ -187,39 +198,74 @@ bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
/******************************************************************************
* *
-* Paramètres : token = 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). *
+* Paramètres : token = encadrement de motif à consulter. *
* *
-* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* Description : Indique si seuls des mots entiers sont retenus des analyses. *
* *
-* Retour : Bilan de l'opération à renvoyer. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_string_token_enroll__old(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool g_string_token_target_fullword(const GStringToken *token)
{
- bool result; /* Statut à retourner */
- GStringTokenClass *class; /* Classe de l'instance */
+ bool result; /* Statut à renvoyer */
+
+ result = token->fullword;
- assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
+ return result;
- class = G_STRING_TOKEN_GET_CLASS(token);
+}
- result = class->enroll(token, context, backend, maxsize);
+
+/******************************************************************************
+* *
+* Paramètres : token = encadrement de motif à consulter. *
+* *
+* Description : Détermine si le gestionnaire est à vocation privée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_string_token_is_private(const GStringToken *token)
+{
+ bool result; /* Statut à renvoyer */
+
+ result = token->private;
return result;
}
+
+/******************************************************************************
+* *
+* Paramètres : token = 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 : - *
+* *
+******************************************************************************/
+
bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
{
bool result; /* Statut à retourner */
- result = g_scan_token_node_enroll(token->root, context, backend, maxsize);
+ token->need_backward = g_scan_token_node_setup_tree(token->root);
+
+ result = g_scan_token_node_enroll(token->root, context, backend, maxsize, &token->slow);
+
+ printf("need backward? %d\n", token->need_backward);
return result;
@@ -241,19 +287,59 @@ bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBa
* *
******************************************************************************/
-void g_string_token_check__old(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
{
- GStringTokenClass *class; /* Classe de l'instance */
+ size_t p; /* Boucle de parcours #3 */
+ match_area_t *pending; /* Correspondance à traiter */
+ vmpa2t pos; /* Tête de lecture */
+ const bin_t *byte; /* Octet à valider */
- class = G_STRING_TOKEN_GET_CLASS(token);
+ g_scan_token_node_check_forward(token->root, context, content, matches);
- class->check(token, context, content, matches);
+ if (token->need_backward)
+ g_scan_token_node_check_backward(token->root, context, content, matches);
-}
+ sort_and_filter_pending_matches(matches);
-void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
- g_scan_token_node_check(token->root, context, content, matches, NULL);
+ if (token->fullword)
+ {
+ reset_pending_matches_ttl(matches);
+
+ for (p = 0; p < matches->used; p++)
+ {
+ pending = &matches->areas[p];
+
+ /* Validation de l'octet précédent, s'il existe */
+ if (pending->start > matches->content_start)
+ {
+ init_vmpa(&pos, pending->start - 1, VMPA_NO_VIRTUAL);
+
+ byte = g_binary_content_get_raw_access(content, &pos, 1);
+
+ if (isalnum(*byte))
+ continue;
+
+ }
+
+ /* Validation de l'octet suivant, s'il existe */
+ if (pending->end < matches->content_end)
+ {
+ init_vmpa(&pos, pending->end, VMPA_NO_VIRTUAL);
+
+ byte = g_binary_content_get_raw_access(content, &pos, 1);
+
+ if (isalnum(*byte))
+ continue;
+
+ }
+
+ keep_pending_match(pending);
+
+ }
+
+ purge_pending_matches(matches);
+
+ }
}
@@ -284,6 +370,9 @@ static void g_string_token_output_to_text(const GStringToken *pattern, GScanCont
size_t count; /* Quantité de cette liste */
size_t i; /* Boucle de parcours */
+ if (g_string_token_is_private(pattern))
+ return;
+
matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
for (i = 0; i < count; i++)
@@ -318,6 +407,9 @@ static void g_string_token_output_to_json(const GStringToken *pattern, GScanCont
size_t k; /* Boucle de parcours #2 */
bool trailing; /* Virgule finale */
+ if (g_string_token_is_private(pattern))
+ return;
+
matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
/* Nombre de correspondances */
diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h
index 879d912..b361ecc 100644
--- a/src/analysis/scan/patterns/token.h
+++ b/src/analysis/scan/patterns/token.h
@@ -52,6 +52,12 @@ typedef struct _GStringTokenClass GStringTokenClass;
/* Indique le type défini pour une bribe de recherche textuelle. */
GType g_string_token_get_type(void);
+/* Indique si seuls des mots entiers sont retenus des analyses. */
+bool g_string_token_target_fullword(const GStringToken *);
+
+/* Détermine si le gestionnaire est à vocation privée. */
+bool g_string_token_is_private(const GStringToken *);
+
/* Inscrit la définition d'un motif dans un moteur de recherche. */
bool g_string_token_enroll(GStringToken *, GScanContext *, GEngineBackend *, size_t);
diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am
index 7fb515f..f0ab3d5 100644
--- a/src/analysis/scan/patterns/tokens/Makefile.am
+++ b/src/analysis/scan/patterns/tokens/Makefile.am
@@ -8,6 +8,7 @@ libanalysisscanpatternstokens_la_SOURCES = \
hex.h hex.c \
node-int.h \
node.h node.c \
+ offset.h offset.c \
plain-int.h \
plain.h plain.c
diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c
index fcb585d..52f239c 100644
--- a/src/analysis/scan/patterns/tokens/atom.c
+++ b/src/analysis/scan/patterns/tokens/atom.c
@@ -251,6 +251,7 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
/******************************************************************************
* *
* 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. *
@@ -261,7 +262,7 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
* *
******************************************************************************/
-sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t count)
+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 */
@@ -274,16 +275,20 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
size_t divisor; /* Taille de la découpe */
size_t quotient; /* Reste de la position */
- count *= 2;
-
/* 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 */
@@ -294,7 +299,7 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
check = 1;
#endif
- for (i = 0; i < src->len; i++)
+ for (i = atom->pos; i < (atom->pos + atom->len); i++)
{
ch = src->data[i];
@@ -315,8 +320,8 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
replaced *= 2;
#ifndef NDEBUG
- check++;
- assert((check - 1) <= count);
+ check *= 2;
+ assert(check <= count);
#endif
}
@@ -326,7 +331,51 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
}
- assert((check - 1) == count);
+ assert(check == count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : byte = octet partiel à interpréter. *
+* mask = valeur du masque à appliquer. *
+* produced = nombre de contenus générés. [OUT] *
+* *
+* Description : Etablit la liste des cas de figures avec un octet partiel. *
+* *
+* Retour : Liste de toutes les combinaisons possibles. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+sized_binary_t *make_atoms_from_masked_byte(bin_t value, bin_t mask, size_t *produced)
+{
+ sized_binary_t *result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ *produced = 16;
+
+ /* Création du réceptacle */
+
+ result = malloc(16 * sizeof(tracked_scan_atom_t));
+
+ /* Remplissage */
+
+ for (i = 0; i < 16; i++)
+ {
+ result[i].data = malloc(1);
+ result[i].len = 1;
+
+ if (mask == 0x0f)
+ result[i].data[0] = value | (i << 4);
+ else
+ result[i].data[0] = value | i;
+
+ }
return result;
diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h
index daa1f16..2fbc19e 100644
--- a/src/analysis/scan/patterns/tokens/atom.h
+++ b/src/analysis/scan/patterns/tokens/atom.h
@@ -58,7 +58,10 @@ int finish_quality_rating(const bitfield_t *, size_t);
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 *, size_t);
+sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, const tracked_scan_atom_t *, size_t);
+
+/* Etablit la liste des cas de figures avec un octet partiel. */
+sized_binary_t *make_atoms_from_masked_byte(bin_t, bin_t, size_t *);
/* Enregistre l'atome déterminé d'une série d'octets. */
bool enroll_prepared_atom(const sized_binary_t *, GScanContext *, GEngineBackend *, tracked_scan_atom_t *);
diff --git a/src/analysis/scan/patterns/tokens/hex-int.h b/src/analysis/scan/patterns/tokens/hex-int.h
index f0460c8..440f693 100644
--- a/src/analysis/scan/patterns/tokens/hex-int.h
+++ b/src/analysis/scan/patterns/tokens/hex-int.h
@@ -49,7 +49,7 @@ struct _GScanHexBytesClass
/* Met en place un gestionnaire de recherche de binaire. */
-bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *);
+bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *, bool);
diff --git a/src/analysis/scan/patterns/tokens/hex.c b/src/analysis/scan/patterns/tokens/hex.c
index c1cdbdf..1fda597 100644
--- a/src/analysis/scan/patterns/tokens/hex.c
+++ b/src/analysis/scan/patterns/tokens/hex.c
@@ -58,12 +58,6 @@ static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *, GScanContext
/* 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);
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-//static bool g_scan_hex_bytes_enroll(GScanHexBytes *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-//static void g_scan_hex_bytes_check(const GScanHexBytes *, GScanContext *, GBinContent *, pending_matches_t *);
-
/* ---------------------------------------------------------------------------------- */
@@ -91,7 +85,6 @@ static void g_scan_hex_bytes_class_init(GScanHexBytesClass *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);
@@ -103,11 +96,6 @@ static void g_scan_hex_bytes_class_init(GScanHexBytesClass *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;
- token = G_STRING_TOKEN_CLASS(klass);
-
- //token->enroll = (enroll_token_fc)g_scan_hex_bytes_enroll;
- //token->check = (check_token_fc)g_scan_hex_bytes_check;
-
}
@@ -170,6 +158,7 @@ static void g_scan_hex_bytes_finalize(GScanHexBytes *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. *
* *
@@ -179,13 +168,13 @@ static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes)
* *
******************************************************************************/
-GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
+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))
+ if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root, private))
g_clear_object(&result);
return result;
@@ -197,6 +186,7 @@ GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
* *
* 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. *
* *
@@ -206,11 +196,11 @@ GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
* *
******************************************************************************/
-bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root)
+bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root, bool private)
{
bool result; /* Bilan à retourner */
- result = g_string_token_create(G_STRING_TOKEN(bytes), root);
+ result = g_string_token_create(G_STRING_TOKEN(bytes), root, false, private);
return result;
@@ -267,191 +257,3 @@ static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *pattern, GScanC
/* TODO */
}
-
-#if 0
-
-/******************************************************************************
-* *
-* 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_scan_hex_bytes_enroll(GScanHexBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
-{
- 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 (bytes->modifier == NULL)
- {
- bytes->raw = malloc(sizeof(sized_binary_t));
- bytes->count = 1;
-
- szstrdup(&bytes[0].raw[0], &bytes->orig);
-
- result = true;
-
- }
- else
- result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count);
-
- if (!result)
- goto exit;
-
- /* Préparation pour la mémorisation des atomes */
-
- bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t));
-
- /* Recherche des atomes */
-
- for (i = 0; i < bytes->count; i++)
- {
- if (bytes->flags & SPBF_CASE_INSENSITIVE)
- {
- find_best_atom(&bytes->raw[i], maxsize, &atom, &letters);
-
- if (letters == 0)
- bytes->atoms[i] = atom;
-
- /* Insertion des combinaisons pour couvrir toutes les casses */
- else
- {
- for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
- ;
-
- extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count);
-
- remaining = bytes->count - i - 1;
-
- bytes->count += (extra_count - 1);
-
- bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t));
-
- memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->raw[i + k] = extra[k];
-
- free(extra);
-
- bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->atoms[i + k] = atom;
-
- i += extra_count - 1;
-
- }
-
- }
-
- else
- find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters);
-
- }
-
- /* Enregistrements en masse */
-
-
- for (i = 0; i < bytes->count && result; i++)
- result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]);
-
- exit:
-
- 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_scan_hex_bytes_check(const GScanHexBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
- size_t i; /* Boucle de parcours #1 */
- const sized_binary_t *raw; /* Données brutes d'origine */
- const tracked_scan_atom_t *atom; /* Atome correspondant */
- size_t count; /* Quantité de bribes trouvées */
- const phys_t *found; /* Localisations des bribes */
- size_t k; /* Boucle de parcours #2 */
- 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 */
-
- for (i = 0; i < bytes->count; i++)
- {
- raw = &bytes->raw[i];
- atom = &bytes->atoms[i];
-
- found = g_scan_context_get_atom_matches(context, atom->pid, &count);
-
- for (k = 0; k < count; k++)
- {
- start = found[k] - atom->pos;
-
- init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
-
- /* Validation du contenu avant l'atome */
-
- if (atom->pos > 0)
- {
- ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
-
- ret = memcmp(raw->data, ptr, atom->pos);
- if (ret != 0) continue;
-
- }
-
- /* 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);
-
- ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
- if (ret != 0) continue;
-
- }
-
- /* Mémorisation de la correspondance */
-
- add_pending_matches(matches, start, raw->len);
-
- }
-
- }
-
-}
-
-#endif
diff --git a/src/analysis/scan/patterns/tokens/hex.h b/src/analysis/scan/patterns/tokens/hex.h
index 1db8eb6..fe5268c 100644
--- a/src/analysis/scan/patterns/tokens/hex.h
+++ b/src/analysis/scan/patterns/tokens/hex.h
@@ -52,7 +52,7 @@ typedef struct _GScanHexBytesClass GScanHexBytesClass;
GType g_scan_hex_bytes_get_type(void);
/* Construit un gestionnaire de recherche de texte brut. */
-GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *);
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *, bool);
diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h
index c543cbf..091a5be 100644
--- a/src/analysis/scan/patterns/tokens/node-int.h
+++ b/src/analysis/scan/patterns/tokens/node-int.h
@@ -28,12 +28,33 @@
#include "node.h"
+#include "offset.h"
+
+
+
+/* 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_node; /* Premier noeud de traitement */
+ GScanTokenNode *last_node; /* Dernier noeud de traitement */
+
+ 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 *, GScanContext *, GEngineBackend *, size_t);
+typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
/* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
/* Décomposition d'un motif de recherche en atomes (instance) */
@@ -41,6 +62,8 @@ 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) */
@@ -48,11 +71,29 @@ struct _GScanTokenNodeClass
{
GObjectClass parent; /* A laisser en premier */
+ apply_scan_token_node_flags_fc apply; /* Prise en compte de fanions */
+
+ visit_scan_token_node_fc visit; /* Phase de répérage initial */
enroll_scan_token_node_fc enroll; /* Inscription d'un motif */
- check_scan_token_node_fc check; /* Conversion en trouvailles */
+
+ 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void _g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void _g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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
index 224328a..1354fff 100644
--- a/src/analysis/scan/patterns/tokens/node.c
+++ b/src/analysis/scan/patterns/tokens/node.c
@@ -28,6 +28,7 @@
#include "node-int.h"
+#include "nodes/any.h"
@@ -35,7 +36,7 @@
/* Initialise la classe des éléments de décomposition. */
-static void g_scan_token_node_class_init(GScanTokenNodeClass *klass);
+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 *);
@@ -95,6 +96,7 @@ static void g_scan_token_node_class_init(GScanTokenNodeClass *klass)
static void g_scan_token_node_init(GScanTokenNode *node)
{
+ node->flags = STNF_NONE;
}
@@ -139,10 +141,148 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
/******************************************************************************
* *
+* 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 */
+
+ if (node->flags & STNF_PROD)
+ {
+ if (points->first_node == NULL)
+ points->first_node = node;
+
+ points->last_node = node;
+
+ }
+
+ 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_node = NULL;
+ points.last_node = NULL;
+
+ points.first_plain = NULL;
+ points.best_masked = NULL;
+
+ g_scan_token_node_visit(node, &points);
+
+ /* Phase d'application */
+
+ //g_scan_token_node_set_flags(points.first_node, STNF_FIRST);
+ //g_scan_token_node_set_flags(points.last_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;//points.first_node;
+
+ g_scan_token_node_set_flags(main, STNF_MAIN);
+
+ printf("main : %p (%s)\n", main, G_OBJECT_TYPE_NAME(main));
+
+ result = (main != node/*points.first_node*/);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* 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.*
* *
@@ -152,16 +292,45 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
* *
******************************************************************************/
-bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool _g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, 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, context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+
assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
- class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+ *slow = 0;
- result = class->enroll(node, context, backend, maxsize);
+ result = _g_scan_token_node_enroll(node, context, backend, maxsize, slow);
return result;
@@ -175,6 +344,8 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
* content = accès au contenu brut pour vérifications (optim.) *
* matches = suivi des correspondances à consolider. *
* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* skip = détermine si l'analyse est différée. [OUT] *
* *
* Description : Transforme les correspondances locales en trouvailles. *
* *
@@ -184,12 +355,236 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
* *
******************************************************************************/
-void g_scan_token_node_check(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset)
+void _g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
{
GScanTokenNodeClass *class; /* Classe de l'instance */
+ if (node->flags & STNF_MAIN)
+ {
+ //assert(*skip); //REMME
+ *skip = false;
+ }
+
+ printf("Checking forward... node=%p / %s skip=%d main=%u\n",
+ node, G_OBJECT_TYPE_NAME(node), *skip, (node->flags & STNF_MAIN) == STNF_MAIN);
+
class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
- class->check(node, context, content, matches, offset);
+ class->check_forward(node, context, content, matches, offset, not, skip);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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 : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+{
+ 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(&offset);
+
+ skip = true;
+
+ _g_scan_token_node_check_forward(node, context, content, matches, &offset, false, &skip);
+
+ /**
+ * 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_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); */
+
+ disable_all_ranges_in_node_search_offset(&offset);
+
+ }
+
+ assert(offset.used == 0);
+
+ exit_node_search_offset(&offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ printf("Checking backward... node=%p / %s skip=%d main=%u\n",
+ node, G_OBJECT_TYPE_NAME(node), *skip, (node->flags & STNF_MAIN) == STNF_MAIN);
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ class->check_backward(node, context, content, matches, offset, not, skip);
+
+ if (node->flags & STNF_MAIN)
+ {
+ //assert(*skip); //REMME
+ *skip = false;
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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 : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+{
+ 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(&offset);
+
+ skip = true;
+
+ _g_scan_token_node_check_backward(node, context, content, matches, &offset, false, &skip);
+
+ /**
+ * 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);
+
+ exit_node_search_offset(&offset);
}
diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h
index 4c9eb48..a2e3b0d 100644
--- a/src/analysis/scan/patterns/tokens/node.h
+++ b/src/analysis/scan/patterns/tokens/node.h
@@ -49,28 +49,38 @@ typedef struct _GScanTokenNode GScanTokenNode;
typedef struct _GScanTokenNodeClass GScanTokenNodeClass;
+/* Propriétés particulières pour noeud d'analyse */
+typedef enum _ScanTokenNodeFlags
+{
+ STNF_NONE = (0 << 0), /* Absence de singularité */
+ STNF_PROD = (1 << 0), /* Absence de singularité */
+ STNF_FIRST = (1 << 1), /* Premier noeud de traitement */ /* REMME ? */
+ STNF_LAST = (1 << 2), /* Dernier noeud de traitement */ /* REMME ? */
+ STNF_MAIN = (1 << 3), /* 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);
+/* Indique les propriétés particulières d'un noeud d'analyse. */
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *);
-// TODO
-// validate
-// force_plain_registration // set begin/end
+/* 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 *, GScanContext *, GEngineBackend *, size_t);
+bool g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
-/* Mémorisation d'une souplesse dans les positions visées */
-typedef struct _node_search_offset_t
-{
- phys_t min; /* Position minimale */
- phys_t max; /* Position maxnimale */
-
-} node_search_offset_t;
+/* Transforme les correspondances locales en trouvailles. */
+void g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
/* Transforme les correspondances locales en trouvailles. */
-void g_scan_token_node_check(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+void g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
diff --git a/src/analysis/scan/patterns/tokens/nodes/Makefile.am b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
index c20beaf..b5da1ee 100644
--- a/src/analysis/scan/patterns/tokens/nodes/Makefile.am
+++ b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
@@ -3,10 +3,18 @@ noinst_LTLIBRARIES = libanalysisscanpatternstokensnodes.la
libanalysisscanpatternstokensnodes_la_SOURCES = \
- hub-int.h \
- hub.h hub.c \
+ 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
+ plain.h plain.c \
+ sequence-int.h \
+ sequence.h sequence.c
libanalysisscanpatternstokensnodes_la_CFLAGS = $(LIBGOBJ_CFLAGS)
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..705aab3
--- /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 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..af2ae29
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.c
@@ -0,0 +1,425 @@
+
+/* 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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->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)
+{
+ g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(any), STNF_PROD);
+
+ 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 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);
+
+ }
+
+ any->has_max = (max != NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* 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_any_enroll(GScanTokenNodeAny *node, GScanContext *context, 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. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ bool initialized; /* Initialisation du suivi ? */
+ bool forced; /* Inclusion dans un scan ? */
+ phys_t size; /* Quantité d'octets considérés*/
+ const phys_t *datasize; /* Taille max. à communiquer */
+
+ if (*skip)
+ return;
+
+
+ // $a = { [1-3] 6f }
+ // pas d'initialisation, construction de résultats avec une taille nulle
+
+
+
+ initialized = are_pending_matches_initialized(matches);
+
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+ size = matches->content_end - matches->content_start;
+
+ datasize = (not ? &size : NULL);
+
+ if (forced)
+ {
+ assert(!initialized);
+
+ if (node->min > size)
+ /* TODO set abort in matches */;
+
+ else
+ add_range_to_node_search_offset(offset,
+ matches->content_start,
+ matches->content_end - matches->content_start,
+ datasize);
+
+ }
+ else
+ {
+ assert(initialized);
+
+
+ // TODO : compléter les intervales éventuels déjà en place
+
+
+ printf("[i] create hole: %llx <-> %llx\n",
+ (unsigned long long)node->min,
+ (unsigned long long)node->max);
+
+
+
+ if (node->has_max)
+ add_range_to_node_search_offset(offset, node->min, node->max, datasize);
+ else
+ add_range_to_node_search_offset(offset, node->min, matches->content_end - node->min, datasize);
+
+ // TODO : si dernier, virer les correspondances qui n'ont plus l'espace de fin requis
+ // -> au niveau du noeud, en fonction du flag _LAST
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ phys_t size; /* Quantité d'octets considérés*/
+ const phys_t *datasize; /* Taille max. à communiquer */
+
+ 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(are_pending_matches_initialized(matches));
+
+ /**
+ * 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
+
+ size = matches->content_end - matches->content_start;
+
+ if (node->min > size)
+ /* TODO set abort in matches */;
+
+ else
+ {
+ datasize = (not ? &size : NULL);
+
+ /**
+ * Une tolérance basée sur des espaces (et non des positions) est déterminée
+ * ici.
+ *
+ * Charge au prochain noeud de traitement de filtrer les résultats courants
+ * avec, voire à la fonction _g_scan_token_node_check_backward() de
+ * réaliser une synthèse finale si le noeud courant est le dernier d'une
+ * lignée.
+ */
+
+ if (node->has_max)
+ add_range_to_node_search_offset(offset, node->min, node->max, datasize);
+ else
+ add_range_to_node_search_offset(offset, node->min, matches->content_end - node->min, datasize);
+
+ }
+
+}
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..6a5628a
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.h
@@ -0,0 +1,58 @@
+
+/* 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 *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub-int.h b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
index df05112..77a4058 100644
--- a/src/analysis/scan/patterns/tokens/nodes/hub-int.h
+++ b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub-int.h - prototypes internes pour un groupe de décompositions de motif de recherche en atomes assemblés
+ * choice-int.h - prototypes internes pour des décompositions alternatives de motif de recherche
*
* Copyright (C) 2023 Cyrille Bagard
*
@@ -21,26 +21,29 @@
*/
-#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H
-#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
-#include "hub.h"
+#include "choice.h"
#include "../node-int.h"
-/* Groupe de décompositions de motif de recherche en atomes (instance) */
-struct _GScanTokenNodeHub
+/* 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 */
+
};
-/* Groupe de décompositions de motif de recherche en atomes (classe) */
-struct _GScanTokenNodeHubClass
+/* Décompositions alternatives de motif de recherche (classe) */
+struct _GScanTokenNodeChoiceClass
{
GScanTokenNodeClass parent; /* A laisser en premier */
@@ -48,4 +51,4 @@ struct _GScanTokenNodeHubClass
-#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H */
+#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..df6ae45
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.c
@@ -0,0 +1,486 @@
+
+/* 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 "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 --------------------- */
+
+
+/* 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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->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->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 à 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_node = NULL;
+ tmp_points.last_node = NULL;
+
+ 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. *
+* 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_choice_enroll(GScanTokenNodeChoice *node, GScanContext *context, 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], context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ pending_matches_t init_matches; /* Correspondances initiales */
+ node_search_offset_t init_offset; /* Intervales initiaux */
+ size_t new_offset; /* Décompte d'intervales */
+ size_t i; /* Boucle de parcours */
+ pending_matches_t tmp_matches; /* Copie locale de travail #1 */
+ node_search_offset_t tmp_offset; /* Copie locale de travail #2 */
+
+ if (*skip)
+ return;
+
+ /* Copie des contextes de départ */
+
+ copy_pending_matches(&init_matches, matches);
+
+ exit_pending_matches(matches);
+ init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end);
+
+ copy_node_search_offset(&init_offset, offset);
+
+ exit_node_search_offset(offset);
+ init_node_search_offset(offset);
+
+ /* Lancement des sous-traitements */
+
+ new_offset = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ copy_pending_matches(&tmp_matches, &init_matches);
+ copy_node_search_offset(&tmp_offset, &init_offset);
+
+ _g_scan_token_node_check_forward(node->children[i], context, content,
+ &tmp_matches, &tmp_offset, not, skip);
+
+ merge_pending_matches(matches, &tmp_matches);
+ merge_node_search_offset(offset, &tmp_offset);
+
+ if (tmp_offset.used > 0)
+ new_offset++;
+
+ exit_pending_matches(&tmp_matches);
+ exit_node_search_offset(&tmp_offset);
+
+ }
+
+ /* Sortie propre */
+
+ exit_pending_matches(&init_matches);
+ exit_node_search_offset(&init_offset);
+
+ /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+
+ if (new_offset != node->count)
+ {
+ assert(node->count > 1);
+ add_range_to_node_search_offset(offset, 0, 0, NULL);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offsets = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ pending_matches_t init_matches; /* Correspondances initiales */
+ node_search_offset_t init_offset; /* Intervales initiaux */
+ size_t new_offset; /* Décompte d'intervales */
+ size_t i; /* Boucle de parcours */
+ pending_matches_t tmp_matches; /* Copie locale de travail #1 */
+ node_search_offset_t tmp_offset; /* Copie locale de travail #2 */
+
+ if (*skip)
+ return;
+
+ /* Copie des contextes de départ */
+
+ copy_pending_matches(&init_matches, matches);
+
+ exit_pending_matches(matches);
+ init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end);
+
+ copy_node_search_offset(&init_offset, offset);
+
+ exit_node_search_offset(offset);
+ init_node_search_offset(offset);
+
+ /* Lancement des sous-traitements */
+
+ new_offset = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ copy_pending_matches(&tmp_matches, &init_matches);
+ copy_node_search_offset(&tmp_offset, &init_offset);
+
+ _g_scan_token_node_check_backward(node->children[i], context, content,
+ &tmp_matches, &tmp_offset, not, skip);
+
+ merge_pending_matches(matches, &tmp_matches);
+ merge_node_search_offset(offset, &tmp_offset);
+
+ if (tmp_offset.used > 0)
+ new_offset++;
+
+ exit_pending_matches(&tmp_matches);
+ exit_node_search_offset(&tmp_offset);
+
+ }
+
+ /* Sortie propre */
+
+ exit_pending_matches(&init_matches);
+ exit_node_search_offset(&init_offset);
+
+ /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+
+ if (new_offset != node->count)
+ {
+ assert(node->count > 1);
+ add_range_to_node_search_offset(offset, 0, 0, NULL);
+ }
+
+}
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/hub.c b/src/analysis/scan/patterns/tokens/nodes/hub.c
deleted file mode 100644
index a11531d..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub.c
+++ /dev/null
@@ -1,150 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub.c - groupe de décompositions de 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 "hub.h"
-
-
-#include "hub-int.h"
-
-
-
-/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
-
-
-/* Initialise la classe des groupes de décompositions. */
-static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass);
-
-/* Initialise une instance de groupe de décompositions. */
-static void g_scan_token_node_hub_init(GScanTokenNodeHub *);
-
-/* Supprime toutes les références externes. */
-static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *);
-
-
-
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* DECOMPOSITION DE MOTIF RECHERCHE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */
-G_DEFINE_TYPE(GScanTokenNodeHub, g_scan_token_node_hub, G_TYPE_SCAN_TOKEN_NODE);
-
-
-/******************************************************************************
-* *
-* Paramètres : klass = classe à initialiser. *
-* *
-* Description : Initialise la classe des groupes de décompositions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass)
-{
- GObjectClass *object; /* Autre version de la classe */
-
- object = G_OBJECT_CLASS(klass);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_hub_dispose;
- object->finalize = (GObjectFinalizeFunc)g_scan_token_node_hub_finalize;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : hub = instance à initialiser. *
-* *
-* Description : Initialise une instance de groupe de décompositions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_init(GScanTokenNodeHub *hub)
-{
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : hub = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *hub)
-{
- G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->dispose(G_OBJECT(hub));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : hub = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *hub)
-{
- G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->finalize(G_OBJECT(hub));
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
-
-
-
-
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.h b/src/analysis/scan/patterns/tokens/nodes/hub.h
deleted file mode 100644
index b2cb0fc..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub.h
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub.h - prototypes pour un groupe de décompositions de 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_NODES_HUB_H
-#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H
-
-
-#include <glib-object.h>
-
-
-#include "../node.h"
-
-
-
-#define G_TYPE_SCAN_TOKEN_NODE_HUB g_scan_token_node_hub_get_type()
-#define G_SCAN_TOKEN_NODE_HUB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHub))
-#define G_IS_SCAN_TOKEN_NODE_HUB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_HUB))
-#define G_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass))
-#define G_IS_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_HUB))
-#define G_SCAN_TOKEN_NODE_HUB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass))
-
-
-/* Groupe de décompositions de motif de recherche en atomes (instance) */
-typedef struct _GScanTokenNodeHub GScanTokenNodeHub;
-
-/* Groupe de décompositions de motif de recherche en atomes (classe) */
-typedef struct _GScanTokenNodeHubClass GScanTokenNodeHubClass;
-
-
-/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */
-GType g_scan_token_node_hub_get_type(void);
-
-
-
-#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_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..9eb8712
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
@@ -0,0 +1,63 @@
+
+/* 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 */
+ tracked_scan_atom_t *atoms; /* Atomes correspondants */
+ size_t count; /* Taille de cette liste */
+ 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..25f0315
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.c
@@ -0,0 +1,814 @@
+
+/* 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* 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 *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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->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->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)
+{
+ g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(masked), STNF_PROD);
+
+ masked->bytes = NULL;
+ masked->len = 0;
+
+ masked->raw = NULL;
+ masked->atoms = NULL;
+ masked->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->count; i++)
+ exit_szstr(&masked->raw[i]);
+
+ if (masked->raw != NULL)
+ free(masked->raw);
+
+ if (masked->atoms != NULL)
+ free(masked->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. *
+* 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_masked_enroll(GScanTokenNodeMasked *node, GScanContext *context, 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);
+
+ /**
+ * 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->raw = make_atoms_from_masked_byte(node->bytes[0].value, node->bytes[0].mask, &node->count);
+
+ node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t));
+
+ for (i = 0; i < node->count && result; i++)
+ {
+ find_best_atom(&node->raw[i], maxsize, &node->atoms[i], NULL);
+
+ result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]);
+
+ }
+
+ node->enrolled_count = node->count;
+
+ }
+
+ }
+
+ 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. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ bool initialized; /* Initialisation du suivi ? */
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t i; /* Boucle de parcours #1 */
+ const tracked_scan_atom_t *atom; /* Atome correspondant */
+ size_t count; /* Quantité de bribes trouvées */
+ const phys_t *found; /* Localisations des bribes */
+ size_t k; /* Boucle de parcours #2 */
+ phys_t new_begin; /* Nouveau départ à tester */
+ size_t o; /* Boucle de parcours #3 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ bool status; /* Bilan d'une correspondance */
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t p; /* Boucle de parcours #4 */
+ match_area_t *pending; /* Correspondance à traiter */
+ phys_t after; /* Espace disposible après */
+ phys_t min; /* Borne minimale déterminée */
+ phys_t max; /* Borne maximale déterminée */
+ phys_t j; /* Boucle de parcours #5 */
+
+ if (*skip)
+ return;
+
+ initialized = are_pending_matches_initialized(matches);
+
+ /**
+ * 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((!initialized && forced) || (initialized && (!forced || not)));
+#endif
+
+ ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
+
+ /* Si aucune correspondance n'a été établie */
+ if (!initialized)
+ {
+ for (i = 0; i < node->enrolled_count; i++)
+ {
+ atom = &node->atoms[i];
+
+ found = g_scan_context_get_atom_matches(context, atom->pid, &count);
+
+ for (k = 0; k < count; k++)
+ {
+ assert(atom->pos == 0);
+
+ new_begin = found[k];
+
+ /**
+ * Si des bornes sont spécifiées, la position de l'atome est testée.
+ *
+ * Dans la pratique, cette situation (non initialisée) ne peut provenir
+ * que d'un espace situé dans le vide, donc couvrant un large périmètre.
+ * La validation a ainsi de grandes chances de passer...
+ *
+ * Le motif pouvant amener à cette situation (pas d'initialisation,
+ * mais à décalage à considérer) est par exemple :
+ *
+ * ~( ?? ?1 )
+ *
+ */
+ if (ocount > 0)
+ {
+ if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
+ continue;
+ }
+
+ /**
+ * Existe-t-il assez de place pour faire tenir le motif masqué ?
+ */
+ if ((new_begin + node->len) > matches->content_end)
+ continue;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ /**
+ * Il ne peut y avoir qu'une seule séquence d'octets à un même
+ * emplacement, donc le couple (start, len) enregistré est
+ * unique.
+ */
+ add_pending_match(matches, new_begin, node->len);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Si les correspondances en place sont à confirmer et compléter */
+ else
+ {
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ assert(pending->end <= matches->content_end);
+
+ after = matches->content_end - pending->end;
+
+ new_begin = pending->end;
+
+ if (ocount > 0)
+ {
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ /**
+ * Si bornes de tolérance il y a, l'espace restant est validé en
+ * tenant compte de ces bornes.
+ */
+ if (!get_node_offset_range(range, node->len, after, &min, &max))
+ continue;
+
+ /**
+ * Une recherche des différentes correspondances amont est lancée.
+ */
+ for (j = min; j <= max; j++)
+ {
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ new_begin + j, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ /**
+ * S'il s'avère qu'il existe de multiples correspondances dans l'espace
+ * analysé, c'est la fonction extend_pending_match_ending() qui
+ * duplique cette correspondance, en s'appuyant sur le TTL pour
+ * repérer ce cas de figure.
+ *
+ * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2'
+ * sont valides pour un même contenu :
+ *
+ * aa.bbb -> correspondance 'aa.bb'
+ * ^
+ *
+ * aa.bbb -> correspondance 'aa..bb'
+ * ^
+ */
+ extend_pending_match_ending(matches, p, new_begin + j + node->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ 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.
+ */
+ if (node->len > after)
+ continue;
+
+ new_begin = pending->end;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ extend_pending_match_ending(matches, p, new_begin + node->len);
+
+ /**
+ * Comme il n'y a qu'une seule itération par correspondance,
+ * nul besoin de recharcher l'élément.
+ */
+
+ }
+
+ }
+
+ }
+
+ purge_pending_matches(matches);
+
+ }
+
+ set_pending_matches_initialized(matches);
+
+ disable_all_ranges_in_node_search_offset(offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offsets = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t p; /* Boucle de parcours #1 */
+ const match_area_t *pending; /* Correspondance à traiter */
+ phys_t before; /* Espace disposible avant */
+ phys_t new_begin; /* Nouveau départ à tester */
+ size_t o; /* Boucle de parcours #2 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ phys_t min; /* Borne minimale déterminée */
+ phys_t max; /* Borne maximale déterminée */
+ phys_t j; /* Boucle de parcours #3 */
+ bool status; /* Bilan d'une correspondance */
+
+ 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(are_pending_matches_initialized(matches));
+
+ /**
+ * 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
+
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ assert(matches->content_start <= pending->start);
+
+ before = pending->start - matches->content_start;
+
+ printf(" (masked) pending: %u - len=%u\n",
+ (unsigned int)pending->start, (unsigned int)node->len);
+
+ new_begin = pending->start - node->len;
+
+ if (ocount > 0)
+ {
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ /**
+ * Si bornes de tolérance il y a, l'espace restant est validé en
+ * tenant compte de ces bornes.
+ */
+ if (!get_node_offset_range(range, node->len, before, &min, &max))
+ {
+ if (not)
+ extend_pending_match_beginning(matches, p, pending->start - node->len);
+
+ continue;
+
+ }
+
+ /**
+ * Une recherche des différentes correspondances amont est lancée.
+ */
+ for (j = min; j <= max; j++)
+ {
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ new_begin - j, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ /**
+ * S'il s'avère qu'il existe de multiples correspondances dans l'espace
+ * analysé, c'est la fonction extend_pending_match_beginning() qui
+ * duplique cette correspondance, en s'appuyant sur le TTL pour
+ * repérer ce cas de figure.
+ */
+ extend_pending_match_beginning(matches, p, new_begin);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si le début 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.
+ */
+ if (node->len > before)
+ {
+ if (not)
+ extend_pending_match_beginning(matches, p, new_begin);
+
+ continue;
+
+ }
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+ printf(" (masked) found new @ %llx ? %d\n",
+ (unsigned long long)new_begin, status);
+
+
+ if ((status && !not) || (!status && not))
+ extend_pending_match_beginning(matches, p, new_begin);
+
+ }
+
+ }
+
+ purge_pending_matches(matches);
+
+ disable_all_ranges_in_node_search_offset(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..d1765fa
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.h
@@ -0,0 +1,72 @@
+
+/* 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;
+
+
+/* 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;
+
+
+/* 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..c54a66f
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.c
@@ -0,0 +1,364 @@
+
+/* 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 "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 --------------------- */
+
+
+/* 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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->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->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(&not->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 = 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. *
+* 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_not_enroll(GScanTokenNodeNot *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+
+ result = _g_scan_token_node_enroll(node->child, context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ 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);
+
+
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, 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
index a38359d..2077c6f 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain-int.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
@@ -28,8 +28,8 @@
#include "plain.h"
-#include "../node-int.h"
#include "../atom.h"
+#include "../node-int.h"
@@ -56,7 +56,7 @@ struct _GScanTokenNodePlainClass
};
-/* Met en place un un noeud représentant un motif textuel. */
+/* Met en place un noeud représentant un motif textuel. */
bool g_scan_token_node_plain_create(GScanTokenNodePlain *, const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
index ee87c73..5a7f976 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.c
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -24,7 +24,11 @@
#include "plain.h"
+#include <assert.h>
+
+
#include "plain-int.h"
+#include "../../../../../common/extstr.h"
@@ -32,7 +36,7 @@
/* Initialise la classe des noeuds pour motif textuel. */
-static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass);
+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 *);
@@ -48,14 +52,20 @@ static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *);
/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* 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 *, GScanContext *, GEngineBackend *, size_t );
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GScanContext *, GEngineBackend *, size_t, size_t *);
/* 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 *, phys_t, GBinContent *);
+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_plain_bytes_check(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
@@ -92,8 +102,10 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
node = G_SCAN_TOKEN_NODE_CLASS(klass);
+ 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->check = (check_scan_token_node_fc)g_scan_plain_bytes_check;
+ 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;
}
@@ -112,6 +124,8 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
static void g_scan_token_node_plain_init(GScanTokenNodePlain *plain)
{
+ g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(plain), STNF_PROD);
+
init_szstr(&plain->orig);
plain->modifier = NULL;
plain->flags = SPNF_NONE;
@@ -203,6 +217,7 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTok
}
+
/******************************************************************************
* *
* Paramètres : plain = encadrement de motif à initialiser pleinement. *
@@ -210,7 +225,7 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTok
* modifier = transformateur éventuel à solliciter. *
* flags = particularités à prendre en considération. *
* *
-* Description : Met en place un un noeud représentant un motif textuel. *
+* Description : Met en place un noeud représentant un motif textuel. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -239,6 +254,29 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
}
+/******************************************************************************
+* *
+* 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;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
@@ -247,10 +285,32 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
/******************************************************************************
* *
+* 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)
+{
+ if (points->first_plain == NULL)
+ points->first_plain = G_SCAN_TOKEN_NODE(node);
+
+}
+
+
+/******************************************************************************
+* *
* 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.*
* *
@@ -260,7 +320,7 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
* *
******************************************************************************/
-static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
{
bool result; /* Statut à retourner */
size_t i; /* Boucle de parcours #1 */
@@ -312,13 +372,14 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
if (letters == 0)
node->atoms[i] = atom;
- /* Insertion des combinaisons pour couvrir toutes les casses */
+ /* Insertion des nouvelles combinaisons pour couvrir toutes les casses */
else
{
- for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
+ /* extra_count = 2^letters */
+ for (k = 1, extra_count = 2; k < letters; k++, extra_count *= 2)
;
- extra = make_atoms_case_insensitive(&node->raw[i], extra_count);
+ extra = make_atoms_case_insensitive(&node->raw[i], &atom, extra_count);
remaining = node->count - i - 1;
@@ -333,7 +394,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
free(extra);
- node->atoms = realloc(node->raw, node->count * sizeof(tracked_scan_atom_t));
+ node->atoms = realloc(node->atoms, node->count * sizeof(tracked_scan_atom_t));
for (k = 0; k < extra_count; k++)
node->atoms[i + k] = atom;
@@ -365,6 +426,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
* *
* 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.) *
* *
@@ -376,7 +438,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
* *
******************************************************************************/
-static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, phys_t start, GBinContent *content)
+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 */
@@ -393,7 +455,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
{
ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
- ret = memcmp(raw->data, ptr, atom->pos);
+ if (nocase)
+ ret = memcasecmp(raw->data, ptr, atom->pos);
+ else
+ ret = memcmp(raw->data, ptr, atom->pos);
+
if (ret != 0) goto done;
}
@@ -406,7 +472,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
- ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+ 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;
}
@@ -427,6 +497,8 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
* content = accès au contenu brut pour vérifications (optim.) *
* matches = suivi des correspondances à consolider. *
* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* skip = détermine si l'analyse est différée. [OUT] *
* *
* Description : Transforme les correspondances locales en trouvailles. *
* *
@@ -436,22 +508,33 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
* *
******************************************************************************/
-static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset)
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
{
bool initialized; /* Initialisation du suivi ? */
+ bool nocase; /* Pas d'intérêt pour la casse */
+ size_t ocount; /* Quantité de bornes présentes*/
size_t i; /* Boucle de parcours #1 */
const sized_binary_t *raw; /* Données brutes d'origine */
const tracked_scan_atom_t *atom; /* Atome correspondant */
size_t count; /* Quantité de bribes trouvées */
const phys_t *found; /* Localisations des bribes */
size_t k; /* Boucle de parcours #2 */
- phys_t start; /* Point de départ */
+ phys_t new_begin; /* Nouveau départ à tester */
bool status; /* Bilan d'une correspondance */
size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
size_t p; /* Boucle de parcours #3 */
+ const match_area_t *pending; /* Correspondance à traiter */
+
+ if (*skip)
+ return;
initialized = are_pending_matches_initialized(matches);
+ nocase = (node->flags & SPNF_CASE_INSENSITIVE);
+
+ get_node_search_offset_ranges(offset, &ocount);
+
for (i = 0; i < node->count; i++)
{
raw = &node->raw[i];
@@ -463,28 +546,34 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
{
for (k = 0; k < count; k++)
{
- start = found[k] - atom->pos;
+ new_begin = found[k] - atom->pos;
/**
* Si personne n'a manipulé les pré-résultats, mais qu'un décallage
* est spécifié par un noeud précédent, une validation sur la base
* d'une position 0 est menée.
*/
- if (offset != NULL)
+ if (ocount > 0)
{
- if (start < offset->min || start > offset->max)
+ if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
+ {
+ if (not)
+ add_pending_match(matches, new_begin, raw->len);
+
continue;
+
+ }
}
- status = check_scan_token_node_plain_content(raw, atom, start, content);
+ status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
- if (status)
+ if ((status && !not) || (!status && not))
/**
* Il ne peut y avoir qu'une seule séquence d'octets à un même
- * emplacement, donc le couple (start, len) enregistré est
+ * emplacement, donc le couple (new_begin, len) enregistré est
* unique.
*/
- add_pending_match(matches, start, raw->len);
+ add_pending_match(matches, new_begin, raw->len);
}
@@ -494,12 +583,17 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
{
reset_pending_matches_ttl(matches);
- pcount = count_pending_matches(matches);
+ pending_ptr = get_all_pending_matches(matches, &pcount);
for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ assert(matches->content_start <= pending->start);
+
for (k = 0; k < count; k++)
{
- start = found[k] - atom->pos;
+ new_begin = found[k] - atom->pos;
/**
* Si bornes de tolérance il y a, on valide la position.
@@ -507,20 +601,52 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
* Sinon les correspondances passées et actuelle doivent
* être jointes.
*/
- if (offset != NULL)
+ if (ocount > 0)
{
- if (!has_pending_match_ending_between(matches, p, start, offset->min, offset->max))
+ if (!does_node_search_offset_include_pos_forward(offset, pending->end, new_begin))
+ {
+ if (not)
+ {
+ extend_pending_match_ending(matches, p, pending->end + raw->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
continue;
+
+ }
}
else
{
- if (!has_pending_match_ending_at(matches, p, start))
+ if (pending->end != new_begin)
+ {
+ if (not)
+ {
+ extend_pending_match_ending(matches, p, pending->end + raw->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
continue;
+
+ }
}
- status = check_scan_token_node_plain_content(raw, atom, start, content);
+ status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
- if (status)
+ if ((status && !not) || (!status && not))
{
/**
* Même si une base de couples uniques est assurée,
@@ -559,18 +685,28 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
/**
* La seconde situation est prise en compte par la fonction
- * extend_pending_match() qui s'appuie sur le TTL pour dupliquer
- * la correspondance pending[x] initiale. Le nouvel élément est
- * placé en fin de liste, ce qui ne boulverse pas le parcours
- * de liste courant, la valeur de pcount n'étant pas actualisée.
+ * extend_pending_match_ending() qui s'appuie sur le TTL pour
+ * dupliquer la correspondance pending[x] initiale. Le nouvel
+ * élément est placé en fin de liste, ce qui ne boulverse pas
+ * le parcours de liste courant, la valeur de pcount n'étant
+ * pas actualisée.
*/
- extend_pending_match(matches, p, start + raw->len);
+ extend_pending_match_ending(matches, p, new_begin + raw->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
}
}
+ }
+
purge_pending_matches(matches);
}
@@ -579,4 +715,42 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
set_pending_matches_initialized(matches);
+ disable_all_ranges_in_node_search_offset(offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+
+
+
+ if (*skip)
+ return;
+
+
+
+ printf("TODO\n");
+ assert(0);
+
+
+
}
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h
index 33e7feb..c8f3920 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.h
@@ -52,9 +52,16 @@ typedef struct _GScanTokenNodePlainClass GScanTokenNodePlainClass;
/* Propriétés d'un élément textuel à rechercher */
typedef enum _ScanPlainNodeFlags
{
- SPNF_NONE = 0x0, /* Aucune particularité */
- SPNF_CASE_INSENSITIVE = 0x1, /* Ignorance de la casse */
- SPNF_FULL_WORD = 0x2, /* Recherche de mot entier */
+ 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;
@@ -65,6 +72,9 @@ 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 *);
+
#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..ad332fc
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c
@@ -0,0 +1,360 @@
+
+/* 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 "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 --------------------- */
+
+
+/* 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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->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->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)
+{
+ sequence->children = realloc(sequence->children, ++sequence->count * sizeof(GScanTokenNode *));
+
+ sequence->children[sequence->count - 1] = child;
+ g_object_ref(G_OBJECT(child));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* 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_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. *
+* 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_sequence_enroll(GScanTokenNodeSequence *node, GScanContext *context, 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], context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ _g_scan_token_node_check_forward(node->children[i], context, content, matches, offset, not, skip);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = 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. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, 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], context, content, matches, offset, not, 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..fc181c6
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.h
@@ -0,0 +1,61 @@
+
+/* 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 *);
+
+
+
+#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..010ec67
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.c
@@ -0,0 +1,352 @@
+
+/* 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. *
+* 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. *
+* 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..b458717
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.h
@@ -0,0 +1,101 @@
+
+/* 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, lors que 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 */
+
+} 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 *);
+
+
+
+
+
+
+/* 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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+#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
index 40a71b5..5748160 100644
--- a/src/analysis/scan/patterns/tokens/plain-int.h
+++ b/src/analysis/scan/patterns/tokens/plain-int.h
@@ -38,14 +38,6 @@ struct _GScanPlainBytes
{
GStringToken parent; /* A laisser en premier */
- sized_binary_t orig; /* Motif d'origine avant modifs*/
- GScanTokenModifier *modifier; /* Transformateur pour le motif*/
- ScanPlainBytesFlags 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 */
-
};
/* Encadrement d'une recherche de texte brut (classe) */
@@ -57,7 +49,7 @@ struct _GScanPlainBytesClass
/* Met en place un gestionnaire de recherche de texte brut. */
-bool g_scan_plain_bytes_create(GScanPlainBytes *, const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags);
+bool g_scan_plain_bytes_create(GScanPlainBytes *, GScanTokenNode *);
diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c
index 26e7dfa..2eb6bbc 100644
--- a/src/analysis/scan/patterns/tokens/plain.c
+++ b/src/analysis/scan/patterns/tokens/plain.c
@@ -29,6 +29,7 @@
#include "plain-int.h"
+#include "nodes/plain.h"
@@ -58,12 +59,6 @@ static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *, GScanCont
/* 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);
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_plain_bytes_enroll(GScanPlainBytes *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-static void g_scan_plain_bytes_check(const GScanPlainBytes *, GScanContext *, GBinContent *, pending_matches_t *);
-
/* ---------------------------------------------------------------------------------- */
@@ -91,7 +86,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *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);
@@ -103,11 +97,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *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;
- token = G_STRING_TOKEN_CLASS(klass);
-
- token->enroll = (enroll_token_fc)g_scan_plain_bytes_enroll;
- token->check = (check_token_fc)g_scan_plain_bytes_check;
-
}
@@ -125,13 +114,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
{
- init_szstr(&bytes->orig);
- bytes->modifier = NULL;
- bytes->flags = SPBF_NONE;
-
- bytes->raw = NULL;
- bytes->atoms = NULL;
- bytes->count = 0;
}
@@ -150,8 +132,6 @@ static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
{
- g_clear_object(&bytes->modifier);
-
G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->dispose(G_OBJECT(bytes));
}
@@ -171,19 +151,6 @@ static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
{
- size_t i; /* Boucle de parcours */
-
- exit_szstr(&bytes->orig);
-
- for (i = 0; i < bytes->count; i++)
- exit_szstr(&bytes->raw[i]);
-
- if (bytes->raw != NULL)
- free(bytes->raw);
-
- if (bytes->atoms != NULL)
- free(bytes->atoms);
-
G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->finalize(G_OBJECT(bytes));
}
@@ -191,9 +158,7 @@ static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
/******************************************************************************
* *
-* Paramètres : text = texte brut à rechercher. *
-* modifier = transformateur éventuel à solliciter. *
-* flags = particularités à prendre en considération. *
+* Paramètres : root = représentation du motif à recherche. *
* *
* Description : Construit un gestionnaire de recherche de texte brut. *
* *
@@ -203,25 +168,24 @@ static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
* *
******************************************************************************/
-GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags)
+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), text, modifier, flags))
+ 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. *
-* text = texte brut à rechercher. *
-* modifier = transformateur éventuel à solliciter. *
-* flags = particularités à prendre en considération. *
+* 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. *
* *
@@ -231,21 +195,19 @@ GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenMod
* *
******************************************************************************/
-bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags)
+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 ? */
- result = true;
+ flags = g_scan_token_node_plain_get_flags(G_SCAN_TOKEN_NODE_PLAIN(root));
- szstrdup(&bytes->orig, text);
+ fullword = (flags & SPNF_FULLWORD);
+ private = (flags & SPNF_PRIVATE);
- if (modifier != NULL)
- {
- bytes->modifier = modifier;
- g_object_ref(G_OBJECT(modifier));
- }
-
- bytes->flags = flags;
+ result = g_string_token_create(G_STRING_TOKEN(bytes), root, fullword, private);
return result;
@@ -302,192 +264,3 @@ static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *pattern, GS
/* TODO */
}
-
-
-/******************************************************************************
-* *
-* 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_scan_plain_bytes_enroll(GScanPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
-{
- return false;
-#if 0
- 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 (bytes->modifier == NULL)
- {
- bytes->raw = malloc(sizeof(sized_binary_t));
- bytes->count = 1;
-
- szstrdup(&bytes[0].raw[0], &bytes->orig);
-
- result = true;
-
- }
- else
- result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count);
-
- if (!result)
- goto exit;
-
- /* Préparation pour la mémorisation des atomes */
-
- bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t));
-
- /* Recherche des atomes */
-
- for (i = 0; i < bytes->count; i++)
- {
- if (bytes->flags & SPBF_CASE_INSENSITIVE)
- {
- find_best_atom(&bytes->raw[i], maxsize, &atom, &letters);
-
- if (letters == 0)
- bytes->atoms[i] = atom;
-
- /* Insertion des combinaisons pour couvrir toutes les casses */
- else
- {
- for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
- ;
-
- extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count);
-
- remaining = bytes->count - i - 1;
-
- bytes->count += (extra_count - 1);
-
- bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t));
-
- memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->raw[i + k] = extra[k];
-
- free(extra);
-
- bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->atoms[i + k] = atom;
-
- i += extra_count - 1;
-
- }
-
- }
-
- else
- find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters);
-
- }
-
- /* Enregistrements en masse */
-
-
- for (i = 0; i < bytes->count && result; i++)
- result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]);
-
- exit:
-
- return result;
-#endif
-}
-
-
-/******************************************************************************
-* *
-* 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_scan_plain_bytes_check(const GScanPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
-#if 0
-
- size_t i; /* Boucle de parcours #1 */
- const sized_binary_t *raw; /* Données brutes d'origine */
- const tracked_scan_atom_t *atom; /* Atome correspondant */
- size_t count; /* Quantité de bribes trouvées */
- const phys_t *found; /* Localisations des bribes */
- size_t k; /* Boucle de parcours #2 */
- 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 */
-
- for (i = 0; i < bytes->count; i++)
- {
- raw = &bytes->raw[i];
- atom = &bytes->atoms[i];
-
- found = g_scan_context_get_atom_matches(context, atom->pid, &count);
-
- for (k = 0; k < count; k++)
- {
- start = found[k] - atom->pos;
-
- init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
-
- /* Validation du contenu avant l'atome */
-
- if (atom->pos > 0)
- {
- ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
-
- ret = memcmp(raw->data, ptr, atom->pos);
- if (ret != 0) continue;
-
- }
-
- /* 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);
-
- ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
- if (ret != 0) continue;
-
- }
-
- /* Mémorisation de la correspondance */
-
- add_pending_matches(matches, start, raw->len);
-
- }
-
- }
-#endif
-}
diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h
index 80a0b4d..6ff48d7 100644
--- a/src/analysis/scan/patterns/tokens/plain.h
+++ b/src/analysis/scan/patterns/tokens/plain.h
@@ -28,9 +28,8 @@
#include <glib-object.h>
-#include "../modifier.h"
+#include "node.h"
#include "../../pattern.h"
-#include "../../../../common/szstr.h"
@@ -49,21 +48,11 @@ typedef struct _GScanPlainBytes GScanPlainBytes;
typedef struct _GScanPlainBytesClass GScanPlainBytesClass;
-/* Propriétés d'un élément textuel à rechercher */
-typedef enum _ScanPlainBytesFlags
-{
- SPBF_NONE = 0x0, /* Aucune particularité */
- SPBF_CASE_INSENSITIVE = 0x1, /* Ignorance de la casse */
- SPBF_FULL_WORD = 0x2, /* Recherche de mot entier */
-
-} ScanPlainBytesFlags;
-
-
/* 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(const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags);
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *);
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
index 4727c9d..1d68b80 100644
--- a/src/analysis/scan/rule.c
+++ b/src/analysis/scan/rule.c
@@ -369,6 +369,8 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo
void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *context)
{
GBinContent *content; /* Contenu à manipuler */
+ vmpa2t start; /* Point de début du contenu */
+ vmpa2t end; /* Point de fin du contenu */
pending_matches_t matches; /* Suivi de correspondances */
size_t i; /* Boucle de parcours #1 */
GSearchPattern *pattern; /* Motif à intégrer */
@@ -378,11 +380,14 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c
content = g_scan_context_get_content(context);
+ g_binary_content_compute_start_pos(content, &start);
+ g_binary_content_compute_end_pos(content, &end);
+
/* Consolidation des résultats */
for (i = 0; i < rule->bytes_used; i++)
{
- init_pending_matches(&matches);
+ init_pending_matches(&matches, &start.physical, &end.physical);
pattern = rule->bytes_locals[i];
diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l
index 18594c4..594d4d9 100644
--- a/src/analysis/scan/tokens.l
+++ b/src/analysis/scan/tokens.l
@@ -32,7 +32,7 @@
* *
******************************************************************************/
-static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out)
+static void rost_unescape_string_bytes(const char *src, size_t len, sized_string_t *out)
{
size_t i; /* Boucle de parcours */
bin_t byte; /* Octet à analyser */
@@ -52,30 +52,177 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
switch (next)
{
- case '\a':
+ case 'a':
+ out->data[out->len++] = '\a';
+ break;
+
+ case 'b':
+ out->data[out->len++] = '\b';
+ break;
+
+ case 't':
+ out->data[out->len++] = '\t';
+ break;
+
+ case 'n':
+ out->data[out->len++] = '\n';
+ break;
+
+ case 'v':
+ out->data[out->len++] = '\v';
+ break;
+
+ case 'f':
+ out->data[out->len++] = '\f';
+ break;
+
+ case 'r':
+ out->data[out->len++] = '\r';
+ break;
+
+ case 'e':
+ out->data[out->len++] = '\e';
+ break;
+
+ case '"':
+ out->data[out->len++] = '\"';
+ break;
+
+ case '\\':
out->data[out->len++] = '\\';
break;
- case '\t':
+ case 'x':
+
+ next = src[i + 2];
+
+ switch (next)
+ {
+ case '0' ... '9':
+ out->data[out->len] = (next - '0');
+ break;
+
+ case 'A' ... 'F':
+ out->data[out->len] = 0xa + (next - 'A');
+ break;
+
+ case 'a' ... 'f':
+ out->data[out->len] = 0xa + (next - 'a');
+ break;
+
+ }
+
+ out->data[out->len] <<= 4;
+
+ next = src[i + 3];
+
+ switch (next)
+ {
+ case '0' ... '9':
+ out->data[out->len] |= (next - '0');
+ break;
+
+ case 'A' ... 'F':
+ out->data[out->len] |= 0xa + (next - 'A');
+ break;
+
+ case 'a' ... 'f':
+ out->data[out->len] |= 0xa + (next - 'a');
+ break;
+
+ }
+
+ out->len++;
+
+ i += 2;
+ break;
+
+ }
+
+ i++;
+ break;
+
+ default:
+ out->data[out->len++] = byte;
+ break;
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : src = liste d'octets à traiter. *
+* len = taille de cette liste. *
+* out = série d'octets bruts obtenue. [OUT] *
+* *
+* Description : Transcrit une série d'octets en en remplaçant certains. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out)
+{
+ size_t i; /* Boucle de parcours */
+ bin_t byte; /* Octet à analyser */
+ bin_t next; /* Octet suivant */
+
+ out->len = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ byte = src[i];
+
+ switch (byte)
+ {
+ case '\\':
+
+ next = src[i + 1];
+
+ switch (next)
+ {
+ case 'a':
+ out->data[out->len++] = '\a';
+ break;
+
+ case 'b':
+ out->data[out->len++] = '\b';
+ break;
+
+ case 't':
out->data[out->len++] = '\t';
break;
- case '\n':
+ case 'n':
out->data[out->len++] = '\n';
break;
- case '\v':
+ case 'v':
out->data[out->len++] = '\v';
break;
- case '\f':
+ case 'f':
out->data[out->len++] = '\f';
break;
- case '\r':
+ case 'r':
out->data[out->len++] = '\r';
break;
+ case 'e':
+ out->data[out->len++] = '\e';
+ break;
+
+ case '"':
+ out->data[out->len++] = '\"';
+ break;
+
case '\\':
out->data[out->len++] = '\\';
break;
@@ -91,11 +238,11 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
break;
case 'A' ... 'F':
- out->data[out->len] = 0x10 + (next - 'A');
+ out->data[out->len] = 0xa + (next - 'A');
break;
case 'a' ... 'f':
- out->data[out->len] = 0x10 + (next - 'a');
+ out->data[out->len] = 0xa + (next - 'a');
break;
}
@@ -111,11 +258,11 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
break;
case 'A' ... 'F':
- out->data[out->len] |= 0x10 + (next - 'A');
+ out->data[out->len] |= 0xa + (next - 'A');
break;
case 'a' ... 'f':
- out->data[out->len] |= 0x10 + (next - 'a');
+ out->data[out->len] |= 0xa + (next - 'a');
break;
}
@@ -175,7 +322,7 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
%option yylineno
%option never-interactive
-%x include_path
+%x inc_path
%x rule_intro
%x raw_block
@@ -200,8 +347,12 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
%x comment
+str_not_escaped [^\"\\]
+str_escaped \\a|\\b|\\t|\\n|\\v|\\f|\\r|\\e|\\\"|\\\\|\\x{hbyte}
+str_mixed ({str_not_escaped}|{str_escaped})
hbyte [0-9a-fA-F]{2}
+mbyte (\?[0-9a-fA-F]|[0-9a-fA-F]\?)
reg_allowed [^^$.|/{}()\[\]*+?\\]
reg_allowed_escaped \\^|\\$|\\\.|\\\||\\\/|\\\{|\\\}|\\\(|\\\)|\\\[|\\\]|\\\*|\\\+|\\\?|\\\\
@@ -219,15 +370,35 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
%%
+"include" { PUSH_STATE(inc_path); return INCLUDE; }
+<inc_path>\"{str_not_escaped}+\" {
+ POP_STATE;
-"include" { PUSH_STATE(include_path); return INCLUDE; }
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+<inc_path>\"{str_mixed}+\" {
+ POP_STATE;
+
+ rost_unescape_string_bytes(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+
+ return ESCAPED_TEXT;
+ }
+
+
+%{ /* Définition locale d'une règle */ %}
-<include_path>"\"" {
- POP_STATE;
- *used = 0;
- PUSH_STATE(strlit);
- }
"rule" { PUSH_STATE(rule_intro); return RAW_RULE; }
@@ -295,6 +466,41 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
}
+%{ /* Définitions communes pour la section "bytes:" */ %}
+
+<strings>"fullword" { return FULLWORD; }
+<strings>"nocase" { return NOCASE; }
+<strings>"private" { return PRIVATE; }
+
+<strings>"=" { PUSH_STATE(bytes_value); return ASSIGN; }
+
+
+%{ /* Définition de motif en texte brut */ %}
+
+<bytes_value>\"{str_not_escaped}+\" {
+ POP_STATE;
+
+ yylval->sized_cstring.data = yytext + 1;
+ yylval->sized_cstring.len = yyleng - 2;
+
+ return PLAIN_TEXT;
+ }
+
+<bytes_value>\"{str_mixed}+\" {
+ POP_STATE;
+
+ rost_unescape_string_bytes(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+ yylval->tmp_cstring = tmp_0;
+
+ return ESCAPED_TEXT;
+ }
+
%{ /* Définition de motif en hexadécimal */ %}
@@ -350,26 +556,21 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
break;
case 'A' ... 'F':
- value = 0x10 + (byte - 'A');
+ value = 0xa + (byte - 'A');
break;
case 'a' ... 'f':
- value = 0x10 + (byte - 'a');
+ value = 0xa + (byte - 'a');
break;
}
if (even)
- {
tmp_0->data[tmp_0->len] = (value << 4);
- even = false;
- }
-
else
- {
tmp_0->data[tmp_0->len++] |= value;
- even = true;
- }
+
+ even = !even;
}
@@ -402,6 +603,73 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
}
+ <bytes_hex>{mbyte}([ ]*{mbyte})* {
+ bool even;
+ size_t i;
+ bin_t byte;
+ bin_t value;
+
+ tmp_0->len = 0;
+ tmp_1->len = 0;
+
+ even = true;
+
+ for (i = 0; i < yyleng; i++)
+ {
+ byte = yytext[i];
+
+ switch (byte)
+ {
+ case ' ':
+ continue;
+ break;
+
+ case '?':
+ even = !even;
+ continue;
+ break;
+
+ case '0' ... '9':
+ value = (byte - '0');
+ break;
+
+ case 'A' ... 'F':
+ value = 0xa + (byte - 'A');
+ break;
+
+ case 'a' ... 'f':
+ value = 0xa + (byte - 'a');
+ break;
+
+ }
+
+ if (even)
+ {
+ tmp_0->data[tmp_0->len++] = (value << 4);
+ tmp_1->data[tmp_1->len++] = 0xf0;
+ }
+ else
+ {
+ tmp_0->data[tmp_0->len++] = value;
+ tmp_1->data[tmp_1->len++] = 0x0f;
+ }
+
+ even = !even;
+
+ }
+
+#ifndef NDEBUG
+ /* Pour rendre plus lisibles les impressions de débogage */
+ tmp_0->data[tmp_0->len] = '\0';
+ tmp_1->data[tmp_1->len] = '\0';
+#endif
+
+ yylval->masked.tmp_values = tmp_0;
+ yylval->masked.tmp_masks = tmp_1;
+ return SEMI_MASK;
+
+ }
+
%{ /* Définition d'expressions régulières */ %}
@@ -573,16 +841,6 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
return NAME;
}
-<strings>"=" { PUSH_STATE(bytes_value); return ASSIGN; }
-
-
-<bytes_value>\"[^\"\\]+\" {
- POP_STATE;
- yylval->sized_cstring.data = yytext + 1;
- yylval->sized_cstring.len = yyleng - 2;
- return PLAIN_STRING;
- }
-
@@ -592,7 +850,7 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
PUSH_STATE(bytes_value_raw);
}
-<bytes_value_raw>"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return MASKED_STRING; }
+<bytes_value_raw>"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return 11111/*MASKED_STRING*/; }
<bytes_value_raw>"\\\"" { }//g_bytes_pattern_append_data(*built_pattern, '"', 0xff); }
<bytes_value_raw>"\\t" { }//g_bytes_pattern_append_data(*built_pattern, '\t', 0xff); }