mirror of
https://github.com/VirusTotal/yara.git
synced 2026-10-11 22:49:58 +00:00
Implement xor modifier. (#830)
This commit is contained in:
committed by
Victor M. Alvarez
parent
16c5bad214
commit
2e664c566f
@@ -578,6 +578,48 @@ static int _yr_atoms_case_insensitive(
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// _yr_atoms_xor
|
||||
//
|
||||
// For a given list of atoms returns another list after a single byte xor
|
||||
// has been applied to it.
|
||||
//
|
||||
static int _yr_atoms_xor(
|
||||
YR_ATOM_LIST_ITEM* atoms,
|
||||
YR_ATOM_LIST_ITEM** xor_atoms)
|
||||
{
|
||||
YR_ATOM_LIST_ITEM* atom;
|
||||
YR_ATOM_LIST_ITEM* new_atom;
|
||||
|
||||
int i, j;
|
||||
*xor_atoms = NULL;
|
||||
atom = atoms;
|
||||
|
||||
while (atom != NULL)
|
||||
{
|
||||
for (j = 1; j <= 255; j++)
|
||||
{
|
||||
new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM));
|
||||
|
||||
if (new_atom == NULL)
|
||||
return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
for (i = 0; i < atom->atom_length; i++)
|
||||
new_atom->atom[i] = atom->atom[i] ^ j;
|
||||
|
||||
new_atom->atom_length = yr_min(atom->atom_length, MAX_ATOM_LENGTH);
|
||||
new_atom->forward_code = atom->forward_code;
|
||||
new_atom->backward_code = atom->backward_code;
|
||||
new_atom->backtrack = atom->backtrack;
|
||||
new_atom->next = *xor_atoms;
|
||||
|
||||
*xor_atoms = new_atom;
|
||||
}
|
||||
|
||||
atom = atom->next;
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
//
|
||||
// _yr_atoms_wide
|
||||
//
|
||||
@@ -1185,6 +1227,7 @@ int yr_atoms_extract_from_string(
|
||||
{
|
||||
YR_ATOM_LIST_ITEM* item;
|
||||
YR_ATOM_LIST_ITEM* case_insensitive_atoms;
|
||||
YR_ATOM_LIST_ITEM* xor_atoms;
|
||||
YR_ATOM_LIST_ITEM* wide_atoms;
|
||||
|
||||
int max_quality;
|
||||
@@ -1260,6 +1303,30 @@ int yr_atoms_extract_from_string(
|
||||
*atoms = _yr_atoms_list_concat(*atoms, case_insensitive_atoms);
|
||||
}
|
||||
|
||||
if (flags & STRING_GFLAGS_XOR)
|
||||
{
|
||||
FAIL_ON_ERROR_WITH_CLEANUP(
|
||||
_yr_atoms_xor(*atoms, &xor_atoms),
|
||||
{
|
||||
yr_atoms_list_destroy(*atoms);
|
||||
yr_atoms_list_destroy(xor_atoms);
|
||||
*atoms = NULL;
|
||||
});
|
||||
|
||||
if (flags & STRING_GFLAGS_ASCII ||
|
||||
flags & STRING_GFLAGS_WIDE ||
|
||||
flags & STRING_GFLAGS_NO_CASE)
|
||||
{
|
||||
*atoms = _yr_atoms_list_concat(*atoms, xor_atoms);
|
||||
}
|
||||
else
|
||||
{
|
||||
yr_atoms_list_destroy(*atoms);
|
||||
*atoms = xor_atoms;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+622
-613
File diff suppressed because it is too large
Load Diff
+60
-58
@@ -66,34 +66,35 @@ extern int yara_yydebug;
|
||||
_REGEXP_ = 276,
|
||||
_ASCII_ = 277,
|
||||
_WIDE_ = 278,
|
||||
_NOCASE_ = 279,
|
||||
_FULLWORD_ = 280,
|
||||
_AT_ = 281,
|
||||
_FILESIZE_ = 282,
|
||||
_ENTRYPOINT_ = 283,
|
||||
_ALL_ = 284,
|
||||
_ANY_ = 285,
|
||||
_IN_ = 286,
|
||||
_OF_ = 287,
|
||||
_FOR_ = 288,
|
||||
_THEM_ = 289,
|
||||
_MATCHES_ = 290,
|
||||
_CONTAINS_ = 291,
|
||||
_IMPORT_ = 292,
|
||||
_TRUE_ = 293,
|
||||
_FALSE_ = 294,
|
||||
_OR_ = 295,
|
||||
_AND_ = 296,
|
||||
_EQ_ = 297,
|
||||
_NEQ_ = 298,
|
||||
_LT_ = 299,
|
||||
_LE_ = 300,
|
||||
_GT_ = 301,
|
||||
_GE_ = 302,
|
||||
_SHIFT_LEFT_ = 303,
|
||||
_SHIFT_RIGHT_ = 304,
|
||||
_NOT_ = 305,
|
||||
UNARY_MINUS = 306
|
||||
_XOR_ = 279,
|
||||
_NOCASE_ = 280,
|
||||
_FULLWORD_ = 281,
|
||||
_AT_ = 282,
|
||||
_FILESIZE_ = 283,
|
||||
_ENTRYPOINT_ = 284,
|
||||
_ALL_ = 285,
|
||||
_ANY_ = 286,
|
||||
_IN_ = 287,
|
||||
_OF_ = 288,
|
||||
_FOR_ = 289,
|
||||
_THEM_ = 290,
|
||||
_MATCHES_ = 291,
|
||||
_CONTAINS_ = 292,
|
||||
_IMPORT_ = 293,
|
||||
_TRUE_ = 294,
|
||||
_FALSE_ = 295,
|
||||
_OR_ = 296,
|
||||
_AND_ = 297,
|
||||
_EQ_ = 298,
|
||||
_NEQ_ = 299,
|
||||
_LT_ = 300,
|
||||
_LE_ = 301,
|
||||
_GT_ = 302,
|
||||
_GE_ = 303,
|
||||
_SHIFT_LEFT_ = 304,
|
||||
_SHIFT_RIGHT_ = 305,
|
||||
_NOT_ = 306,
|
||||
UNARY_MINUS = 307
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
@@ -118,41 +119,42 @@ extern int yara_yydebug;
|
||||
#define _REGEXP_ 276
|
||||
#define _ASCII_ 277
|
||||
#define _WIDE_ 278
|
||||
#define _NOCASE_ 279
|
||||
#define _FULLWORD_ 280
|
||||
#define _AT_ 281
|
||||
#define _FILESIZE_ 282
|
||||
#define _ENTRYPOINT_ 283
|
||||
#define _ALL_ 284
|
||||
#define _ANY_ 285
|
||||
#define _IN_ 286
|
||||
#define _OF_ 287
|
||||
#define _FOR_ 288
|
||||
#define _THEM_ 289
|
||||
#define _MATCHES_ 290
|
||||
#define _CONTAINS_ 291
|
||||
#define _IMPORT_ 292
|
||||
#define _TRUE_ 293
|
||||
#define _FALSE_ 294
|
||||
#define _OR_ 295
|
||||
#define _AND_ 296
|
||||
#define _EQ_ 297
|
||||
#define _NEQ_ 298
|
||||
#define _LT_ 299
|
||||
#define _LE_ 300
|
||||
#define _GT_ 301
|
||||
#define _GE_ 302
|
||||
#define _SHIFT_LEFT_ 303
|
||||
#define _SHIFT_RIGHT_ 304
|
||||
#define _NOT_ 305
|
||||
#define UNARY_MINUS 306
|
||||
#define _XOR_ 279
|
||||
#define _NOCASE_ 280
|
||||
#define _FULLWORD_ 281
|
||||
#define _AT_ 282
|
||||
#define _FILESIZE_ 283
|
||||
#define _ENTRYPOINT_ 284
|
||||
#define _ALL_ 285
|
||||
#define _ANY_ 286
|
||||
#define _IN_ 287
|
||||
#define _OF_ 288
|
||||
#define _FOR_ 289
|
||||
#define _THEM_ 290
|
||||
#define _MATCHES_ 291
|
||||
#define _CONTAINS_ 292
|
||||
#define _IMPORT_ 293
|
||||
#define _TRUE_ 294
|
||||
#define _FALSE_ 295
|
||||
#define _OR_ 296
|
||||
#define _AND_ 297
|
||||
#define _EQ_ 298
|
||||
#define _NEQ_ 299
|
||||
#define _LT_ 300
|
||||
#define _LE_ 301
|
||||
#define _GT_ 302
|
||||
#define _GE_ 303
|
||||
#define _SHIFT_LEFT_ 304
|
||||
#define _SHIFT_RIGHT_ 305
|
||||
#define _NOT_ 306
|
||||
#define UNARY_MINUS 307
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 215 "grammar.y" /* yacc.c:1915 */
|
||||
#line 216 "grammar.y" /* yacc.c:1915 */
|
||||
|
||||
EXPRESSION expression;
|
||||
SIZED_STRING* sized_string;
|
||||
@@ -163,7 +165,7 @@ union YYSTYPE
|
||||
YR_META* meta;
|
||||
YR_RULE* rule;
|
||||
|
||||
#line 167 "grammar.h" /* yacc.c:1915 */
|
||||
#line 169 "grammar.h" /* yacc.c:1915 */
|
||||
};
|
||||
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
|
||||
@@ -139,6 +139,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
%token <sized_string> _REGEXP_
|
||||
%token _ASCII_
|
||||
%token _WIDE_
|
||||
%token _XOR_
|
||||
%token _NOCASE_
|
||||
%token _FULLWORD_
|
||||
%token _AT_
|
||||
@@ -571,6 +572,7 @@ string_modifier
|
||||
| _ASCII_ { $$ = STRING_GFLAGS_ASCII; }
|
||||
| _NOCASE_ { $$ = STRING_GFLAGS_NO_CASE; }
|
||||
| _FULLWORD_ { $$ = STRING_GFLAGS_FULL_WORD; }
|
||||
| _XOR_ { $$ = STRING_GFLAGS_XOR; }
|
||||
;
|
||||
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define STRING_GFLAGS_GREEDY_REGEXP 0x10000
|
||||
#define STRING_GFLAGS_DOT_ALL 0x20000
|
||||
#define STRING_GFLAGS_DISABLED 0x40000
|
||||
#define STRING_GFLAGS_XOR 0x80000
|
||||
|
||||
#define STRING_IS_HEX(x) \
|
||||
(((x)->g_flags) & STRING_GFLAGS_HEXADECIMAL)
|
||||
@@ -125,6 +126,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define STRING_IS_DISABLED(x) \
|
||||
(((x)->g_flags) & STRING_GFLAGS_DISABLED)
|
||||
|
||||
#define STRING_IS_XOR(x) \
|
||||
(((x)->g_flags) & STRING_GFLAGS_XOR)
|
||||
|
||||
#define STRING_FOUND(x) \
|
||||
((x)->matches[yr_get_tidx()].tail != NULL)
|
||||
|
||||
|
||||
+652
-894
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -173,6 +173,7 @@ octdigit [0-7]
|
||||
"strings" { return _STRINGS_; }
|
||||
"ascii" { return _ASCII_; }
|
||||
"wide" { return _WIDE_; }
|
||||
"xor" { return _XOR_; }
|
||||
"fullword" { return _FULLWORD_; }
|
||||
"nocase" { return _NOCASE_; }
|
||||
"condition" { return _CONDITION_; }
|
||||
@@ -943,4 +944,3 @@ int yr_lex_parse_rules_fd(
|
||||
|
||||
return compiler->errors;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -497,7 +497,8 @@ YR_STRING* yr_parser_reduce_string_declaration(
|
||||
if (strcmp(identifier,"$") == 0)
|
||||
string_flags |= STRING_GFLAGS_ANONYMOUS;
|
||||
|
||||
if (!(string_flags & STRING_GFLAGS_WIDE))
|
||||
if (!(string_flags & STRING_GFLAGS_WIDE) &&
|
||||
!(string_flags & STRING_GFLAGS_XOR))
|
||||
string_flags |= STRING_GFLAGS_ASCII;
|
||||
|
||||
// Hex strings are always handled as DOT_ALL regexps.
|
||||
|
||||
@@ -58,6 +58,63 @@ typedef struct _CALLBACK_ARGS
|
||||
} CALLBACK_ARGS;
|
||||
|
||||
|
||||
static int _yr_scan_xor_compare(
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
uint8_t* string,
|
||||
size_t string_length)
|
||||
{
|
||||
const uint8_t* s1 = data;
|
||||
const uint8_t* s2 = string;
|
||||
uint8_t k = 0;
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
if (data_size < string_length)
|
||||
return 0;
|
||||
|
||||
// Calculate the xor key to compare with. *s1 is the start of the string we
|
||||
// matched on and *s2 is the "plaintext" string, so *s1 ^ *s2 is the key to
|
||||
// every *s2 as we compare.
|
||||
k = *s1 ^ *s2;
|
||||
|
||||
while (i < string_length && *s1++ == ((*s2++) ^ k))
|
||||
i++;
|
||||
|
||||
return (int) ((i == string_length) ? i : 0);
|
||||
}
|
||||
|
||||
static int _yr_scan_xor_wcompare(
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
uint8_t* string,
|
||||
size_t string_length)
|
||||
{
|
||||
const uint8_t* s1 = data;
|
||||
const uint8_t* s2 = string;
|
||||
uint8_t k = 0;
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
if (data_size < string_length * 2)
|
||||
return 0;
|
||||
|
||||
// Calculate the xor key to compare with. *s1 is the start of the string we
|
||||
// matched on and *s2 is the "plaintext" string, so *s1 ^ *s2 is the key to
|
||||
// every *s2 as we compare.
|
||||
k = *s1 ^ *s2;
|
||||
|
||||
while (i < string_length && *s1 == ((*s2) ^ k) && ((*(s1 + 1)) ^ k) == 0x00)
|
||||
{
|
||||
s1+=2;
|
||||
s2++;
|
||||
i++;
|
||||
}
|
||||
|
||||
return (int) ((i == string_length) ? i * 2 : 0);
|
||||
}
|
||||
|
||||
|
||||
static int _yr_scan_compare(
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
@@ -720,6 +777,28 @@ static int _yr_scan_verify_literal_match(
|
||||
string->string,
|
||||
string->length);
|
||||
}
|
||||
|
||||
if (STRING_IS_XOR(string) && forward_matches == 0)
|
||||
{
|
||||
if (STRING_IS_WIDE(string))
|
||||
{
|
||||
forward_matches = _yr_scan_xor_wcompare(
|
||||
data + offset,
|
||||
data_size - offset,
|
||||
string->string,
|
||||
string->length);
|
||||
}
|
||||
|
||||
if (forward_matches == 0)
|
||||
{
|
||||
forward_matches = _yr_scan_xor_compare(
|
||||
data + offset,
|
||||
data_size - offset,
|
||||
string->string,
|
||||
string->length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (forward_matches == 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -477,6 +477,38 @@ static void test_strings()
|
||||
condition:\n\
|
||||
all of them\n\
|
||||
}", "abcdef");
|
||||
|
||||
assert_true_rule_file(
|
||||
"rule test {\n\
|
||||
strings:\n\
|
||||
$a = \"This program cannot\" xor\n\
|
||||
condition:\n\
|
||||
#a == 255\n\
|
||||
}", "tests/data/xor.out");
|
||||
|
||||
assert_true_rule_file(
|
||||
"rule test {\n\
|
||||
strings:\n\
|
||||
$a = \"This program cannot\" xor ascii\n\
|
||||
condition:\n\
|
||||
#a == 256\n\
|
||||
}", "tests/data/xor.out");
|
||||
|
||||
assert_true_rule_file(
|
||||
"rule test {\n\
|
||||
strings:\n\
|
||||
$a = \"This program cannot\" xor wide\n\
|
||||
condition:\n\
|
||||
#a == 256\n\
|
||||
}", "tests/data/xorwide.out");
|
||||
|
||||
assert_true_rule_file(
|
||||
"rule test {\n\
|
||||
strings:\n\
|
||||
$a = \"ab\" xor nocase\n\
|
||||
condition:\n\
|
||||
#a == 1084\n\
|
||||
}", "tests/data/xornocase.out");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user