From fed4c10b9bb1c6f99440dba3839a1e7b56b40359 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 12 Sep 2023 06:43:02 +0200 Subject: Save current state with some ROST extra features. --- configure.ac | 2 + src/analysis/scan/context.c | 6 +- src/analysis/scan/core.c | 34 + src/analysis/scan/exprs/call.c | 2 +- src/analysis/scan/grammar.y | 288 ++++++-- src/analysis/scan/items/Makefile.am | 4 +- src/analysis/scan/items/console/log.c | 17 +- src/analysis/scan/items/math/Makefile.am | 13 + src/analysis/scan/items/math/to_string.c | 381 ++++++++++ src/analysis/scan/items/math/to_string.h | 58 ++ src/analysis/scan/items/string/Makefile.am | 15 + src/analysis/scan/items/string/lower.c | 270 +++++++ src/analysis/scan/items/string/lower.h | 58 ++ src/analysis/scan/items/string/to_int.c | 303 ++++++++ src/analysis/scan/items/string/to_int.h | 58 ++ src/analysis/scan/items/string/upper.c | 270 +++++++ src/analysis/scan/items/string/upper.h | 58 ++ src/analysis/scan/matches/pending.c | 279 +++++-- src/analysis/scan/matches/pending.h | 36 +- src/analysis/scan/patterns/token-int.h | 17 +- src/analysis/scan/patterns/token.c | 140 +++- src/analysis/scan/patterns/token.h | 6 + src/analysis/scan/patterns/tokens/Makefile.am | 1 + src/analysis/scan/patterns/tokens/atom.c | 63 +- src/analysis/scan/patterns/tokens/atom.h | 5 +- src/analysis/scan/patterns/tokens/hex-int.h | 2 +- src/analysis/scan/patterns/tokens/hex.c | 210 +----- src/analysis/scan/patterns/tokens/hex.h | 2 +- src/analysis/scan/patterns/tokens/node-int.h | 47 +- src/analysis/scan/patterns/tokens/node.c | 407 ++++++++++- src/analysis/scan/patterns/tokens/node.h | 34 +- .../scan/patterns/tokens/nodes/Makefile.am | 14 +- src/analysis/scan/patterns/tokens/nodes/any-int.h | 60 ++ src/analysis/scan/patterns/tokens/nodes/any.c | 425 +++++++++++ src/analysis/scan/patterns/tokens/nodes/any.h | 58 ++ .../scan/patterns/tokens/nodes/choice-int.h | 54 ++ src/analysis/scan/patterns/tokens/nodes/choice.c | 486 ++++++++++++ src/analysis/scan/patterns/tokens/nodes/choice.h | 61 ++ src/analysis/scan/patterns/tokens/nodes/hub-int.h | 51 -- src/analysis/scan/patterns/tokens/nodes/hub.c | 150 ---- src/analysis/scan/patterns/tokens/nodes/hub.h | 55 -- .../scan/patterns/tokens/nodes/masked-int.h | 63 ++ src/analysis/scan/patterns/tokens/nodes/masked.c | 814 +++++++++++++++++++++ src/analysis/scan/patterns/tokens/nodes/masked.h | 72 ++ src/analysis/scan/patterns/tokens/nodes/not-int.h | 57 ++ src/analysis/scan/patterns/tokens/nodes/not.c | 364 +++++++++ src/analysis/scan/patterns/tokens/nodes/not.h | 59 ++ .../scan/patterns/tokens/nodes/plain-int.h | 4 +- src/analysis/scan/patterns/tokens/nodes/plain.c | 244 +++++- src/analysis/scan/patterns/tokens/nodes/plain.h | 16 +- .../scan/patterns/tokens/nodes/sequence-int.h | 58 ++ src/analysis/scan/patterns/tokens/nodes/sequence.c | 360 +++++++++ src/analysis/scan/patterns/tokens/nodes/sequence.h | 61 ++ src/analysis/scan/patterns/tokens/offset.c | 352 +++++++++ src/analysis/scan/patterns/tokens/offset.h | 101 +++ src/analysis/scan/patterns/tokens/plain-int.h | 10 +- src/analysis/scan/patterns/tokens/plain.c | 257 +------ src/analysis/scan/patterns/tokens/plain.h | 15 +- src/analysis/scan/rule.c | 7 +- src/analysis/scan/tokens.l | 334 ++++++++- src/common/szstr.h | 6 +- tests/analysis/scan/functions.py | 58 ++ tests/analysis/scan/pyapi.py | 1 - tests/analysis/scan/scanning_hex.py | 691 ++++++++++++++++- tests/analysis/scan/scanning_str.py | 194 +++++ 65 files changed, 7680 insertions(+), 1018 deletions(-) create mode 100644 src/analysis/scan/items/math/Makefile.am create mode 100644 src/analysis/scan/items/math/to_string.c create mode 100644 src/analysis/scan/items/math/to_string.h create mode 100644 src/analysis/scan/items/string/Makefile.am create mode 100644 src/analysis/scan/items/string/lower.c create mode 100644 src/analysis/scan/items/string/lower.h create mode 100644 src/analysis/scan/items/string/to_int.c create mode 100644 src/analysis/scan/items/string/to_int.h create mode 100644 src/analysis/scan/items/string/upper.c create mode 100644 src/analysis/scan/items/string/upper.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/any-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/any.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/any.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/choice-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/choice.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/choice.h delete mode 100644 src/analysis/scan/patterns/tokens/nodes/hub-int.h delete mode 100644 src/analysis/scan/patterns/tokens/nodes/hub.c delete mode 100644 src/analysis/scan/patterns/tokens/nodes/hub.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/masked-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/masked.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/masked.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/not-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/not.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/not.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/sequence-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/sequence.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/sequence.h create mode 100644 src/analysis/scan/patterns/tokens/offset.c create mode 100644 src/analysis/scan/patterns/tokens/offset.h create mode 100644 tests/analysis/scan/scanning_str.py diff --git a/configure.ac b/configure.ac index f9680cb..f2b6c92 100644 --- a/configure.ac +++ b/configure.ac @@ -731,6 +731,8 @@ AC_CONFIG_FILES([Makefile src/analysis/scan/items/Makefile src/analysis/scan/items/console/Makefile src/analysis/scan/items/magic/Makefile + src/analysis/scan/items/math/Makefile + src/analysis/scan/items/string/Makefile src/analysis/scan/items/time/Makefile src/analysis/scan/matches/Makefile src/analysis/scan/patterns/Makefile 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 + #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 -%type PLAIN_STRING -%type MASKED_STRING +%type PLAIN_TEXT +%type ESCAPED_TEXT %type HEX_BYTES %type FULL_MASK -%type SEMI_MASK +%type SEMI_MASK %type REGEX_BYTES + +%type str_pattern + %type modifiers %type _modifiers %type chained_modifiers %type mod_stage %type modifier +%type str_flags + + %type hex_pattern %type hex_tokens %type hex_token +%type hex_range +%type 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 . + */ + + +#include "to_string.h" + + +#include +#include + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H +#define _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H + + +#include + + +#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 . + */ + + +#include "lower.h" + + +#include + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H +#define _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H + + +#include + + +#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 . + */ + + +#include "to_int.h" + + +#include + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H +#define _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H + + +#include + + +#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 . + */ + + +#include "upper.h" + + +#include + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H +#define _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H + + +#include + + +#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 #include +#include #include +#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 #include @@ -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 +#include #include @@ -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 . + */ + + +#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 . + */ + + +#include "any.h" + + +#include + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H + + +#include + + +#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/choice-int.h b/src/analysis/scan/patterns/tokens/nodes/choice-int.h new file mode 100644 index 0000000..77a4058 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/choice-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * choice-int.h - prototypes internes pour des décompositions alternatives de motif de recherche + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H + + +#include "choice.h" + + +#include "../node-int.h" + + + +/* Décompositions alternatives de motif de recherche (instance) */ +struct _GScanTokenNodeChoice +{ + GScanTokenNode parent; /* A laisser en premier */ + + GScanTokenNode **children; /* Sous-noeuds à représenter */ + size_t count; /* Taille de cette liste */ + +}; + +/* Décompositions alternatives de motif de recherche (classe) */ +struct _GScanTokenNodeChoiceClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c new file mode 100644 index 0000000..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 . + */ + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H + + +#include + + +#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-int.h b/src/analysis/scan/patterns/tokens/nodes/hub-int.h deleted file mode 100644 index df05112..0000000 --- a/src/analysis/scan/patterns/tokens/nodes/hub-int.h +++ /dev/null @@ -1,51 +0,0 @@ - -/* 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 - * - * 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 . - */ - - -#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H -#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H - - -#include "hub.h" - - -#include "../node-int.h" - - - -/* Groupe de décompositions de motif de recherche en atomes (instance) */ -struct _GScanTokenNodeHub -{ - GScanTokenNode parent; /* A laisser en premier */ - -}; - -/* Groupe de décompositions de motif de recherche en atomes (classe) */ -struct _GScanTokenNodeHubClass -{ - GScanTokenNodeClass parent; /* A laisser en premier */ - -}; - - - -#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_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 . - */ - - -#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 . - */ - - -#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H -#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H - - -#include - - -#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 . + */ + + +#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 . + */ + + +#include "masked.h" + + +#include + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H + + +#include + + +#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 . + */ + + +#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 . + */ + + +#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(¬->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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H + + +#include + + +#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 + + #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 . + */ + + +#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 . + */ + + +#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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H + + +#include + + +#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 . + */ + + +#include "offset.h" + + +#include + + + + + + +/****************************************************************************** +* * +* 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H + + +#include + +#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 -#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; } +\"{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; + } + +\"{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 */ %} -"\"" { - 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:" */ %} + +"fullword" { return FULLWORD; } +"nocase" { return NOCASE; } +"private" { return PRIVATE; } + +"=" { PUSH_STATE(bytes_value); return ASSIGN; } + + +%{ /* Définition de motif en texte brut */ %} + +\"{str_not_escaped}+\" { + POP_STATE; + + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 2; + + return PLAIN_TEXT; + } + +\"{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_]* } + {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; } -"=" { PUSH_STATE(bytes_value); return ASSIGN; } - - -\"[^\"\\]+\" { - 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); } -"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return MASKED_STRING; } +"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return 11111/*MASKED_STRING*/; } "\\\"" { }//g_bytes_pattern_append_data(*built_pattern, '"', 0xff); } "\\t" { }//g_bytes_pattern_append_data(*built_pattern, '\t', 0xff); } diff --git a/src/common/szstr.h b/src/common/szstr.h index 0091482..aad1920 100644 --- a/src/common/szstr.h +++ b/src/common/szstr.h @@ -37,7 +37,11 @@ /* Structure associant une chaîne et sa taille */ typedef struct _sized_string_t { - char *data; /* Chaîne de caractères */ + union { + const char *static_data; /* Données non modifiées */ + char *data; /* Chaîne de caractères */ + }; + size_t len; /* Taille correspondante */ } sized_string_t; diff --git a/tests/analysis/scan/functions.py b/tests/analysis/scan/functions.py index 8553018..96f029f 100644 --- a/tests/analysis/scan/functions.py +++ b/tests/analysis/scan/functions.py @@ -76,6 +76,64 @@ rule test { self.check_rule_success(rule, cnt) + def testMathOperations(self): + """Perform math operations with core functions.""" + + rule = ''' +rule test { + + condition: + math.to_string(123) == "123" + and math.to_string(291, 16) == "0x123" + and math.to_string(-83, 8) == "-0123" + and math.to_string(123, 2) == "0b1111011" + +} +''' + + self.check_rule_success(rule) + + + def testStringOperations(self): + """Perform string operations with core functions.""" + + rule = ''' +rule test { + + condition: + string.lower("ABCd") == "abcd" and string.lower("123abc") == "123abc" + +} +''' + + self.check_rule_success(rule) + + rule = ''' +rule test { + + condition: + string.upper("abcD") == "ABCD" and string.upper("123ABC") == "123ABC" + +} +''' + + self.check_rule_success(rule) + + rule = ''' +rule test { + + condition: + string.to_int("123") == 123 + and string.to_int("123", 16) == 291 + and string.to_int("0x123") == 291 + and string.to_int("-0123") == -83 + +} +''' + + self.check_rule_success(rule) + + def testTime(self): """Check current time.""" diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py index b5b2453..4b066f3 100644 --- a/tests/analysis/scan/pyapi.py +++ b/tests/analysis/scan/pyapi.py @@ -6,7 +6,6 @@ from gi._constants import TYPE_INVALID from pychrysalide.analysis.scan import ScanExpression from pychrysalide.analysis.scan import ScanOptions from pychrysalide.analysis.scan import find_token_modifiers_for_name -from pychrysalide.analysis.scan.patterns.modifiers import PlainModifier from pychrysalide.glibext import ComparableItem diff --git a/tests/analysis/scan/scanning_hex.py b/tests/analysis/scan/scanning_hex.py index e009b79..32979c8 100644 --- a/tests/analysis/scan/scanning_hex.py +++ b/tests/analysis/scan/scanning_hex.py @@ -3,8 +3,218 @@ from common import RostTestClass from pychrysalide.analysis.contents import MemoryContent -class TestRostScanning(RostTestClass): - """TestCases for the bytes section syntax.""" +class TestRostScanningBinary(RostTestClass): + """TestCases for the bytes section syntax (binary).""" + + def testLonelyPatterns(self): + """Evaluate the most simple patterns.""" + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { 41 } + + condition: + #a == 1 and @a[0] == 0 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { 62 } + + condition: + #a == 1 and @a[0] == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { 66 } + + condition: + #a == 1 and @a[0] == 5 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ?1 } + + condition: + #a == 1 and @a[0] == 0 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ?2 } + + condition: + #a == 1 and @a[0] == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ?6 } + + condition: + #a == 1 and @a[0] == 5 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testLonelyPatternsNot(self): + """Evaluate the most simple patterns (not version).""" + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ~41 } + + condition: + #a == 5 and @a[0] == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ~62 } + + condition: + #a == 5 and @a[0] == 0 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ~66 } + + condition: + #a == 5 and @a[4] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ~?1 } + + condition: + #a == 5 and @a[0] == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ~?2 } + + condition: + #a == 5 and @a[0] == 0 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'Abcdef') + + rule = ''' +rule test { + + strings: + $a = { ~?6 } + + condition: + #a == 5 and @a[4] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + def testSimpleHexPattern(self): """Test a simple hex pattern.""" @@ -24,3 +234,480 @@ rule test { ''' self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 2d 41 62 63 } + + condition: + #a == 1 and @a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testSimpleMaskedHexPattern(self): + """Test a simple masked hex pattern.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?1 6? ?3 } + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testHexPatternWithPlainAndMasked(self): + """Test hex patterns with plain and masked bytes.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 41 6? ?3 } + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 4? 62 ?3 } + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 4? ?2 63 } + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 4? ?2 ?3 } + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 2d 4? ?2 63 } + + condition: + #a == 1 and @a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 2d 4? 62 ?3 2d } + + condition: + #a == 1 and @a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 2? 41 6? 63 ?d } + + condition: + #a == 1 and @a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testHexPatternWithPlainAndHoles(self): + """Test hex patterns with plain bytes and holes.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 33 ?? 41 ?? 63 ?? 34 } + + condition: + #a == 1 and @a[0] == 2 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?? 33 ?? 41 ?? 63 ?? 34 ?? } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?? 33 [1-5] 63 ?? 34 ?? } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { [3-4] 41 ?? 63 ?? 34 ?? } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?? 33 ?? 41 ?? 63 [3-] } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testHexPatternWithMaskedAndHoles(self): + """Test hex patterns with masked bytes and holes.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?3 ?? 4? ?? 6? ?? ?4 } + + condition: + #a == 1 and @a[0] == 2 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?? ?3 ?? 4? ?? 6? ?? ?4 ?? } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?? ?3 [1-5] ?3 ?? ?4 ?? } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { [3-4] ?1 ?? ?3 ?? ?4 ?? } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ?? 3? ?? 4? ?? 6? [3-] } + + condition: + #a == 1 and @a[0] == 1 and !a[0] == 9 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testPipedPlainHexPatterns(self): + """Look for several patterns at once with piped definition.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 41 62 ( 63 | 64 | 65 ) } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ( 41 | f2 | f3 ) 62 63 } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 41 ( 61 | 62 | 63 ) 63 } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ( 41 62 63 | 42 62 63 | 43 62 63 ) } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testPipedMaskedHexPatterns(self): + """Look for several patterns at once with piped definition.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 4? 6? ( ?3 | ?4 | ?5 ) } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ( ?1 | ?2 | ?3 ) 6? 6? } + + condition: + console.log("COUNTER: ", #a) and #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 4? ( ?1 | ?2 | ?3 ) 6? } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { ( 4? ?2 ?3 | 4? 6? 6? | ?3 6? ?3 ) } + + condition: + #a == 1 and @a[0] == 4 and !a[0] == 3 + +} +''' + + self.check_rule_success(rule, content=cnt) diff --git a/tests/analysis/scan/scanning_str.py b/tests/analysis/scan/scanning_str.py new file mode 100644 index 0000000..ff36ca3 --- /dev/null +++ b/tests/analysis/scan/scanning_str.py @@ -0,0 +1,194 @@ + +from common import RostTestClass +from pychrysalide.analysis.contents import MemoryContent + + +class TestRostScanningStrings(RostTestClass): + """TestCases for the bytes section syntax (strings).""" + + def testSimpleStringPattern(self): + """Test a simple string pattern.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = "Abc" + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testEscapedStringPattern(self): + """Test escaped string patterns.""" + + cnt = MemoryContent(b'\a\b\t\n\v\f\r' + bytes([ 0x1b ]) + b'"\\\xff') + + rule = r''' +rule test { + + strings: + $a = "\a\b\t\n\v\f\r\e\"\\\xff" + + condition: + #a == 1 and @a[0] == 0 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'\a\b\t\n--123--\v\f\r' + bytes([ 0x1b ]) + b'"\\\xff') + + rule = r''' +rule test { + + strings: + $a = "\a\b\t\n--123--\v\f\r\e\"\\\xff" + + condition: + #a == 1 and @a[0] == 0 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testStringModifiers(self): + """Check string modifiers output.""" + + cnt = MemoryContent(b'--414243--') + + rule = ''' +rule test { + + strings: + $a = "ABC" hex + + condition: + #a == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'--ABC--') + + rule = ''' +rule test { + + strings: + $a = "ABC" plain + + condition: + #a == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'--CBA--') + + rule = ''' +rule test { + + strings: + $a = "ABC" rev + + condition: + #a == 1 + +} +''' + + + def testStringPatternFullword(self): + """Test a fullword string pattern.""" + + cnt = MemoryContent(b'ABCDEF 123 ') + + rule = ''' +rule test { + + strings: + $a = "DEF" fullword + $b = "123" fullword + + condition: + #a == 0 and #b == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'DEF 123 ') + + rule = ''' +rule test { + + strings: + $a = "DEF" fullword + $b = "123" fullword + + condition: + #a == 1 and #b == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + cnt = MemoryContent(b'\tDEF 123 ') + + rule = ''' +rule test { + + strings: + $a = "DEF" fullword + $b = "123" fullword + + condition: + #a == 1 and #b == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) + + + def testStringPatternCase(self): + """Test a string pattern with case care.""" + + cnt = MemoryContent(b'abc123-Abc123Def456GHI...z0z1z2z3z4z5z6z7z8z9') + + rule = ''' +rule test { + + strings: + $a = "Abc" nocase + $b = "ABC123DEF456GHI" nocase + $z = "z0z1z2z3z4z5z6z7z8z9" nocase + + condition: + #a == 2 and #b == 1 and #z == 1 + +} +''' + + self.check_rule_success(rule, content=cnt) -- cgit v0.11.2-87-g4458