Skip to content

Commit 0c1cbee

Browse files
authored
XOR Values. (#1745)
* XOR Values. When the xor modifier is used we have not displayed (or even kept) the xor key. This diff adds a -X option to the CLI that will display the xor key. To do this I am recording the xor key in _yr_scan_xor_compare() and _yr_scan_xor_wcompare() and then populating that in the YR_MATCH structure. This way it is available to the consumers of libyara to handle how they see fit. I'll be adding support for exposing this in yara-python if this PR is accepted. * xor key fixes. Per suggestion from Victor, always display the xor key when -X is specified, even if the string is not an xor string. This makes it more consistent to parse with common tools because the number of fields will always be the same. Also, specify that it is an xor key using "xor(0x01)" format.
1 parent 125e404 commit 0c1cbee

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

cli/yara.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ static bool show_tags = false;
147147
static bool show_stats = false;
148148
static bool show_strings = false;
149149
static bool show_string_length = false;
150+
static bool show_xor_key = false;
150151
static bool show_meta = false;
151152
static bool show_namespace = false;
152153
static bool show_version = false;
@@ -296,6 +297,12 @@ args_option_t options[] = {
296297
&show_string_length,
297298
_T("print length of matched strings")),
298299

300+
OPT_BOOLEAN(
301+
'X',
302+
_T("print-xor-key"),
303+
&show_xor_key,
304+
_T("print xor key of matched strings")),
305+
299306
OPT_BOOLEAN('g', _T("print-tags"), &show_tags, _T("print tags")),
300307

301308
OPT_BOOLEAN(
@@ -1081,7 +1088,7 @@ static int handle_message(
10811088

10821089
// Show matched strings.
10831090

1084-
if (show_strings || show_string_length)
1091+
if (show_strings || show_string_length || show_xor_key)
10851092
{
10861093
YR_STRING* string;
10871094

@@ -1103,6 +1110,9 @@ static int handle_message(
11031110
match->base + match->offset,
11041111
string->identifier);
11051112

1113+
if (show_xor_key)
1114+
_tprintf(_T(":xor(0x%02x)"), match->xor_key);
1115+
11061116
if (show_strings)
11071117
{
11081118
_tprintf(_T(": "));

libyara/include/yara/types.h

+3
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@ struct YR_MATCH
496496

497497
// True if this is match for a private string.
498498
bool is_private;
499+
500+
// Set to the xor key if this is an xor string.
501+
uint8_t xor_key;
499502
};
500503

501504
struct YR_AC_STATE

libyara/scan.c

+35-7
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,16 @@ typedef struct _CALLBACK_ARGS
5555

5656
int forward_matches;
5757
int full_word;
58+
int xor_key;
5859

5960
} CALLBACK_ARGS;
6061

6162
static int _yr_scan_xor_compare(
6263
const uint8_t* data,
6364
size_t data_size,
6465
uint8_t* string,
65-
size_t string_length)
66+
size_t string_length,
67+
uint8_t* xor_key)
6668
{
6769
int result = 0;
6870
const uint8_t* s1 = data;
@@ -94,15 +96,20 @@ _exit:;
9496
string_length,
9597
result);
9698

99+
if (result > 0)
100+
*xor_key = k;
101+
97102
return result;
98103
}
99104

100105
static int _yr_scan_xor_wcompare(
101106
const uint8_t* data,
102107
size_t data_size,
103108
uint8_t* string,
104-
size_t string_length)
109+
size_t string_length,
110+
uint8_t* xor_key)
105111
{
112+
int result = 0;
106113
const uint8_t* s1 = data;
107114
const uint8_t* s2 = string;
108115
uint8_t k = 0;
@@ -124,7 +131,12 @@ static int _yr_scan_xor_wcompare(
124131
i++;
125132
}
126133

127-
return (int) ((i == string_length) ? i * 2 : 0);
134+
result = (int) ((i == string_length) ? i * 2 : 0);
135+
136+
if (result > 0)
137+
*xor_key = k;
138+
139+
return result;
128140
}
129141

130142
static int _yr_scan_compare(
@@ -397,7 +409,8 @@ static int _yr_scan_verify_chained_string_match(
397409
const uint8_t* match_data,
398410
uint64_t match_base,
399411
uint64_t match_offset,
400-
int32_t match_length)
412+
int32_t match_length,
413+
uint8_t xor_key)
401414
{
402415
YR_DEBUG_FPRINTF(
403416
2,
@@ -584,6 +597,7 @@ static int _yr_scan_verify_chained_string_match(
584597
new_match->prev = NULL;
585598
new_match->next = NULL;
586599
new_match->is_private = STRING_IS_PRIVATE(matching_string);
600+
new_match->xor_key = xor_key;
587601

588602
// A copy of the matching data is written to the matches_arena, the
589603
// amount of data copies is limited by YR_CONFIG_MAX_MATCH_DATA.
@@ -687,7 +701,8 @@ static int _yr_scan_match_callback(
687701
match_data,
688702
callback_args->data_base,
689703
match_offset,
690-
match_length);
704+
match_length,
705+
callback_args->xor_key);
691706
}
692707
else
693708
{
@@ -733,6 +748,7 @@ static int _yr_scan_match_callback(
733748
new_match->prev = NULL;
734749
new_match->next = NULL;
735750
new_match->is_private = STRING_IS_PRIVATE(string);
751+
new_match->xor_key = callback_args->xor_key;
736752

737753
FAIL_ON_ERROR(_yr_scan_add_match_to_list(
738754
new_match,
@@ -843,6 +859,8 @@ static int _yr_scan_verify_re_match(
843859
callback_args.data_base = data_base;
844860
callback_args.forward_matches = forward_matches;
845861
callback_args.full_word = STRING_IS_FULL_WORD(ac_match->string);
862+
// xor modifier is not valid for RE but set it so we don't leak stack values.
863+
callback_args.xor_key = 0;
846864

847865
if (ac_match->backward_code != NULL)
848866
{
@@ -886,6 +904,7 @@ static int _yr_scan_verify_literal_match(
886904

887905
int flags = 0;
888906
int forward_matches = 0;
907+
uint8_t xor_key = 0;
889908

890909
CALLBACK_ARGS callback_args;
891910
YR_STRING* string = ac_match->string;
@@ -927,13 +946,21 @@ static int _yr_scan_verify_literal_match(
927946
if (STRING_IS_WIDE(string))
928947
{
929948
forward_matches = _yr_scan_xor_wcompare(
930-
data + offset, data_size - offset, string->string, string->length);
949+
data + offset,
950+
data_size - offset,
951+
string->string,
952+
string->length,
953+
&xor_key);
931954
}
932955

933956
if (forward_matches == 0)
934957
{
935958
forward_matches = _yr_scan_xor_compare(
936-
data + offset, data_size - offset, string->string, string->length);
959+
data + offset,
960+
data_size - offset,
961+
string->string,
962+
string->length,
963+
&xor_key);
937964
}
938965
}
939966
}
@@ -954,6 +981,7 @@ static int _yr_scan_verify_literal_match(
954981
callback_args.data_base = data_base;
955982
callback_args.forward_matches = forward_matches;
956983
callback_args.full_word = STRING_IS_FULL_WORD(string);
984+
callback_args.xor_key = xor_key;
957985

958986
FAIL_ON_ERROR(
959987
_yr_scan_match_callback(data + offset, 0, flags, &callback_args));

0 commit comments

Comments
 (0)