yara 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +2 -0
- data/Gemfile +15 -0
- data/History.txt +6 -0
- data/LICENSE.txt +165 -0
- data/README.rdoc +43 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/ext/yara_native/Match.c +191 -0
- data/ext/yara_native/Match.h +22 -0
- data/ext/yara_native/Rules.c +203 -0
- data/ext/yara_native/Rules.h +12 -0
- data/ext/yara_native/Yara_native.c +20 -0
- data/ext/yara_native/Yara_native.h +9 -0
- data/ext/yara_native/errors.c +11 -0
- data/ext/yara_native/errors.h +9 -0
- data/ext/yara_native/extconf.rb +14 -0
- data/lib/yara.rb +45 -0
- data/samples/ispe.rb +14 -0
- data/samples/upx.rb +39 -0
- data/spec/rules_spec.rb +208 -0
- data/spec/samples/DumpMem.exe +0 -0
- data/spec/samples/packers.yara +118 -0
- data/spec/samples/upx.yara +22 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/yara_spec.rb +8 -0
- metadata +169 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
#include "errors.h"
|
2
|
+
#include "Rules.h"
|
3
|
+
#include "Match.h"
|
4
|
+
#include <stdio.h>
|
5
|
+
|
6
|
+
static VALUE class_Rules = Qnil;
|
7
|
+
|
8
|
+
void rules_mark(YARA_CONTEXT *ctx) { }
|
9
|
+
|
10
|
+
void rules_free(YARA_CONTEXT *ctx) {
|
11
|
+
yr_destroy_context(ctx);
|
12
|
+
}
|
13
|
+
|
14
|
+
VALUE rules_allocate(VALUE klass) {
|
15
|
+
YARA_CONTEXT *ctx = yr_create_context();
|
16
|
+
|
17
|
+
return Data_Wrap_Struct(klass, rules_mark, rules_free, ctx);
|
18
|
+
}
|
19
|
+
|
20
|
+
VALUE rules_compile_file(VALUE self, VALUE rb_fname) {
|
21
|
+
FILE * file;
|
22
|
+
char * fname;
|
23
|
+
YARA_CONTEXT *ctx;
|
24
|
+
char error_message[256];
|
25
|
+
|
26
|
+
Check_Type(rb_fname, T_STRING);
|
27
|
+
fname = RSTRING_PTR(rb_fname);
|
28
|
+
|
29
|
+
if( !(file=fopen(fname, "r")) ) {
|
30
|
+
rb_raise(error_CompileError, "No such file: %s", fname);
|
31
|
+
} else {
|
32
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
33
|
+
|
34
|
+
if( yr_compile_file(file, ctx) != 0 ) {
|
35
|
+
yr_get_error_message(ctx, error_message, sizeof(error_message));
|
36
|
+
fclose(file);
|
37
|
+
rb_raise(error_CompileError, "Syntax Error - %s(%d): %s", fname, ctx->last_error_line, error_message);
|
38
|
+
}
|
39
|
+
|
40
|
+
yr_push_file_name(ctx, fname);
|
41
|
+
fclose(file);
|
42
|
+
return Qtrue;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
VALUE rules_compile_string(VALUE self, VALUE rb_rules) {
|
47
|
+
YARA_CONTEXT *ctx;
|
48
|
+
char *rules;
|
49
|
+
char error_message[256];
|
50
|
+
|
51
|
+
Check_Type(rb_rules, T_STRING);
|
52
|
+
rules = RSTRING_PTR(rb_rules);
|
53
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
54
|
+
|
55
|
+
if( yr_compile_string(rules, ctx) != 0) {
|
56
|
+
yr_get_error_message(ctx, error_message, sizeof(error_message));
|
57
|
+
rb_raise(error_CompileError, "Syntax Error - line(%d): %s", ctx->last_error_line, error_message);
|
58
|
+
}
|
59
|
+
|
60
|
+
return Qtrue;
|
61
|
+
}
|
62
|
+
|
63
|
+
VALUE rules_weight(VALUE self) {
|
64
|
+
YARA_CONTEXT *ctx;
|
65
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
66
|
+
return INT2NUM(yr_calculate_rules_weight(ctx));
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
VALUE rules_current_namespace(VALUE self) {
|
71
|
+
YARA_CONTEXT *ctx;
|
72
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
73
|
+
if(ctx->current_namespace && ctx->current_namespace->name)
|
74
|
+
return rb_str_new2(ctx->current_namespace->name);
|
75
|
+
else
|
76
|
+
return Qnil;
|
77
|
+
}
|
78
|
+
|
79
|
+
VALUE rules_namespaces(VALUE self) {
|
80
|
+
YARA_CONTEXT *ctx;
|
81
|
+
NAMESPACE *ns;
|
82
|
+
VALUE ary = rb_ary_new();
|
83
|
+
|
84
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
85
|
+
ns = ctx->namespaces;
|
86
|
+
while(ns && ns->name) {
|
87
|
+
rb_ary_push(ary, rb_str_new2(ns->name));
|
88
|
+
ns = ns->next;
|
89
|
+
}
|
90
|
+
return ary;
|
91
|
+
}
|
92
|
+
|
93
|
+
NAMESPACE * find_namespace(YARA_CONTEXT *ctx, const char *name) {
|
94
|
+
NAMESPACE *ns = ctx->namespaces;
|
95
|
+
|
96
|
+
while(ns && ns->name) {
|
97
|
+
if(strcmp(name, ns->name) == 0)
|
98
|
+
return(ns);
|
99
|
+
else
|
100
|
+
ns = ns->next;
|
101
|
+
}
|
102
|
+
return (NAMESPACE*) NULL;
|
103
|
+
}
|
104
|
+
|
105
|
+
VALUE rules_set_namespace(VALUE self, VALUE rb_namespace) {
|
106
|
+
YARA_CONTEXT *ctx;
|
107
|
+
NAMESPACE *ns = NULL;
|
108
|
+
const char *name;
|
109
|
+
|
110
|
+
Check_Type(rb_namespace, T_STRING);
|
111
|
+
name = RSTRING_PTR(rb_namespace);
|
112
|
+
|
113
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
114
|
+
|
115
|
+
if (!(ns = find_namespace(ctx, name)))
|
116
|
+
ns = yr_create_namespace(ctx, name);
|
117
|
+
|
118
|
+
if (ns) {
|
119
|
+
ctx->current_namespace = ns;
|
120
|
+
return rb_namespace;
|
121
|
+
} else {
|
122
|
+
return Qnil;
|
123
|
+
}
|
124
|
+
|
125
|
+
}
|
126
|
+
|
127
|
+
static int
|
128
|
+
scan_callback(RULE *rule, unsigned char *buffer, unsigned int buffer_size, void *data) {
|
129
|
+
int match_ret;
|
130
|
+
VALUE match = Qnil;
|
131
|
+
VALUE results = *((VALUE *) data);
|
132
|
+
|
133
|
+
Check_Type(results, T_ARRAY);
|
134
|
+
|
135
|
+
match_ret = Match_NEW_from_rule(rule, buffer, &match);
|
136
|
+
if(match_ret == 0 && !NIL_P(match))
|
137
|
+
rb_ary_push(results,match);
|
138
|
+
|
139
|
+
return match_ret;
|
140
|
+
}
|
141
|
+
|
142
|
+
|
143
|
+
VALUE rules_scan_file(VALUE self, VALUE rb_fname) {
|
144
|
+
YARA_CONTEXT *ctx;
|
145
|
+
VALUE results;
|
146
|
+
unsigned int ret;
|
147
|
+
char *fname;
|
148
|
+
|
149
|
+
Check_Type(rb_fname, T_STRING);
|
150
|
+
results = rb_ary_new();
|
151
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
152
|
+
fname = RSTRING_PTR(rb_fname);
|
153
|
+
|
154
|
+
ret = yr_scan_file(fname, ctx, scan_callback, &results);
|
155
|
+
if (ret == ERROR_COULD_NOT_OPEN_FILE)
|
156
|
+
rb_raise(error_ScanError, "Could not open file: '%s'", fname);
|
157
|
+
else if (ret != 0)
|
158
|
+
rb_raise(error_ScanError, "A error occurred while scanning: %s",
|
159
|
+
((ret > MAX_SCAN_ERROR)? "unknown error" : SCAN_ERRORS[ret]));
|
160
|
+
|
161
|
+
return results;
|
162
|
+
}
|
163
|
+
|
164
|
+
VALUE rules_scan_string(VALUE self, VALUE rb_dat) {
|
165
|
+
YARA_CONTEXT *ctx;
|
166
|
+
VALUE results;
|
167
|
+
char *buf;
|
168
|
+
long buflen;
|
169
|
+
int ret;
|
170
|
+
|
171
|
+
Check_Type(rb_dat, T_STRING);
|
172
|
+
buf = RSTRING_PTR(rb_dat);
|
173
|
+
buflen = RSTRING_LEN(rb_dat);
|
174
|
+
|
175
|
+
results = rb_ary_new();
|
176
|
+
|
177
|
+
Data_Get_Struct(self, YARA_CONTEXT, ctx);
|
178
|
+
|
179
|
+
ret = yr_scan_mem(buf, buflen, ctx, scan_callback, &results);
|
180
|
+
if (ret != 0)
|
181
|
+
rb_raise(error_ScanError, "A error occurred while scanning: %s",
|
182
|
+
((ret > MAX_SCAN_ERROR)? "unknown error" : SCAN_ERRORS[ret]));
|
183
|
+
|
184
|
+
return results;
|
185
|
+
}
|
186
|
+
|
187
|
+
void init_rules(VALUE rb_ns) {
|
188
|
+
|
189
|
+
class_Rules = rb_define_class_under(rb_ns, "Rules", rb_cObject);
|
190
|
+
rb_define_alloc_func(class_Rules, rules_allocate);
|
191
|
+
|
192
|
+
rb_define_method(class_Rules, "compile_file", rules_compile_file, 1);
|
193
|
+
rb_define_method(class_Rules, "compile_string", rules_compile_string, 1);
|
194
|
+
rb_define_method(class_Rules, "weight", rules_weight, 0);
|
195
|
+
rb_define_method(class_Rules, "current_namespace", rules_current_namespace, 0);
|
196
|
+
rb_define_method(class_Rules, "namespaces", rules_namespaces, 0);
|
197
|
+
rb_define_method(class_Rules, "set_namespace", rules_set_namespace, 1);
|
198
|
+
rb_define_method(class_Rules, "scan_file", rules_scan_file, 1);
|
199
|
+
rb_define_method(class_Rules, "scan_string", rules_scan_string, 1);
|
200
|
+
|
201
|
+
init_match(rb_ns);
|
202
|
+
}
|
203
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <yara.h>
|
3
|
+
|
4
|
+
#include "Yara_native.h"
|
5
|
+
#include "Rules.h"
|
6
|
+
#include "errors.h"
|
7
|
+
|
8
|
+
static VALUE module_Yara = Qnil;
|
9
|
+
|
10
|
+
void Init_yara_native() {
|
11
|
+
yr_init();
|
12
|
+
|
13
|
+
module_Yara = rb_define_module("Yara");
|
14
|
+
|
15
|
+
init_errors(module_Yara);
|
16
|
+
init_rules(module_Yara);
|
17
|
+
}
|
18
|
+
|
19
|
+
|
20
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#include "errors.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
|
4
|
+
VALUE error_CompileError = Qnil;
|
5
|
+
VALUE error_ScanError = Qnil;
|
6
|
+
|
7
|
+
void
|
8
|
+
init_errors(VALUE rb_ns) {
|
9
|
+
error_CompileError = rb_define_class_under(rb_ns, "CompileError", rb_eStandardError);
|
10
|
+
error_ScanError = rb_define_class_under(rb_ns, "ScanError", rb_eStandardError);
|
11
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
extension_name = "yara_native"
|
5
|
+
|
6
|
+
dir_config(extension_name)
|
7
|
+
|
8
|
+
unless have_library("yara") and
|
9
|
+
find_header("yara.h", "/usr/local/include")
|
10
|
+
raise "You must install the yara library"
|
11
|
+
end
|
12
|
+
|
13
|
+
create_makefile(extension_name)
|
14
|
+
|
data/lib/yara.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
require 'yara_native'
|
3
|
+
|
4
|
+
module Yara
|
5
|
+
class Rules
|
6
|
+
end
|
7
|
+
|
8
|
+
class Match
|
9
|
+
def to_hash
|
10
|
+
{ :rule => self.rule,
|
11
|
+
:namespace => self.namespace,
|
12
|
+
:tags => self.tags,
|
13
|
+
:meta => self.meta,
|
14
|
+
:strings => self.strings }
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
h=to_hash
|
19
|
+
h.inspect
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MatchString
|
24
|
+
|
25
|
+
alias ident identifier
|
26
|
+
|
27
|
+
def <=>(other)
|
28
|
+
self.offset <=> other.offset
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_a
|
32
|
+
[self.offset, self.ident, self.buffer]
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_hash
|
36
|
+
{ :offset => self.offset, :identifier => self.ident, :buffer => self.buffer}
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
h=to_a
|
41
|
+
h.inspect
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/samples/ispe.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Usage example:
|
4
|
+
# ruby ispe.rb /win_c/windows/system32/*.???
|
5
|
+
#
|
6
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
require 'yara'
|
8
|
+
|
9
|
+
ctx = Yara::Rules.new
|
10
|
+
ctx.compile_string "rule IsPE { condition: uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 }"
|
11
|
+
|
12
|
+
ARGV.each do |fname|
|
13
|
+
ctx.scan_file(fname).each {|match| puts "#{fname} -> #{match.rule}" }
|
14
|
+
end
|
data/samples/upx.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << 'lib'
|
4
|
+
require 'yara'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
rule_str = <<_EOF_
|
8
|
+
rule UPX {
|
9
|
+
strings:
|
10
|
+
$noep1 = { B8 ?? ?? ?? ?? B9 ?? ?? ?? ?? 33 D2 EB 01 0F 56 EB 01 0F E8 03 00 00 00 EB 01 0F EB 01 0F 5E EB 01 }
|
11
|
+
$noep2 = { 5E 89 F7 B9 ?? ?? ?? ?? 8A 07 47 2C E8 3C 01 77 F7 80 3F ?? 75 F2 8B 07 8A 5F 04 66 C1 E8 08 C1 C0 10 86 C4 29 F8 80 EB E8 01 F0 89 07 83 C7 }
|
12
|
+
$noep3 = { 01 DB [0-1] 07 8B 1E 83 EE FC 11 DB [1-4] B8 01 00 00 00 01 DB }
|
13
|
+
$noep4 = { 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 D5 FE FF FF 8B 06 83 F8 00 74 11 8D B5 E1 FE FF FF 8B 06 83 F8 01 0F 84 F1 }
|
14
|
+
$noep5 = { 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB }
|
15
|
+
$noep6 = { FF D5 80 A7 ?? ?? ?? ?? ?? 58 50 54 50 53 57 FF D5 58 61 8D 44 24 ?? 6A 00 39 C4 75 FA 83 EC 80 E9 }
|
16
|
+
$noep7 = { 55 FF 96 ?? ?? ?? ?? 09 C0 74 07 89 03 83 C3 04 EB ?? FF 96 ?? ?? ?? ?? 8B AE ?? ?? ?? ?? 8D BE 00 F0 FF FF BB 00 10 00 00 50 54 6A 04 53 57 }
|
17
|
+
$noep8 = { FF D5 8D 87 ?? ?? ?? ?? 80 20 ?? 80 60 ?? ?? 58 50 54 50 53 57 FF D5 58 61 8D 44 24 ?? 6A 00 39 C4 75 FA 83 EC 80 E9 }
|
18
|
+
$ep1 = { 60 E8 00 00 00 00 58 83 E8 3D }
|
19
|
+
$ep2 = { 60 E8 00 00 00 00 83 CD FF 31 DB 5E }
|
20
|
+
$ep3 = { 50 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD }
|
21
|
+
|
22
|
+
condition: any of ($noep*) or for any of ($ep*) : ($ at entrypoint)
|
23
|
+
}
|
24
|
+
_EOF_
|
25
|
+
|
26
|
+
ctx = Yara::Rules.new
|
27
|
+
ctx.compile_string rule_str
|
28
|
+
|
29
|
+
ARGV.each do |fname|
|
30
|
+
begin
|
31
|
+
ctx.scan_file(fname).each do |match|
|
32
|
+
pp match
|
33
|
+
end
|
34
|
+
rescue Yara::ScanError => e
|
35
|
+
STDERR.puts e
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
data/spec/rules_spec.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Yara::Rules do
|
4
|
+
it "should be a class" do
|
5
|
+
Yara::Rules.should be_kind_of(Class)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should initialize cleanly" do
|
9
|
+
lambda { Yara::Rules.new }.should_not raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
context "Instances" do
|
13
|
+
before(:each) do
|
14
|
+
@rules = Yara::Rules.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should indicate rules weight" do
|
18
|
+
@rules.weight.should be_kind_of(Numeric)
|
19
|
+
@rules.weight.should == 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should compile a file" do
|
23
|
+
lambda { @rules.compile_file(sample_file("upx.yara")) }.should_not raise_error
|
24
|
+
@rules.weight.should > 0
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should compile an empty file" do
|
28
|
+
lambda { @rules.compile_file("/dev/null") }.should_not raise_error
|
29
|
+
@rules.weight.should == 0
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
it "should raise an error if compiling an invalid filename" do
|
34
|
+
lambda { @rules.compile_file("so totally bogus a file") }.should raise_error
|
35
|
+
@rules.weight.should == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise an error if compiling a file with bad syntax" do
|
39
|
+
lambda { @rules.compile_file(__FILE__) }.should raise_error(Yara::CompileError)
|
40
|
+
@rules.weight.should == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should raise an error if duplicate file data is compiled" do
|
44
|
+
lambda { @rules.compile_file(sample_file("upx.yara")) }.should_not raise_error
|
45
|
+
lambda { @rules.compile_file(sample_file("upx.yara")) }.should raise_error(Yara::CompileError)
|
46
|
+
@rules.weight.should > 0
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should compile a string" do
|
50
|
+
rules = File.read(sample_file("upx.yara"))
|
51
|
+
lambda { @rules.compile_string(rules) }.should_not raise_error
|
52
|
+
@rules.weight.should > 0
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should compile an empty string" do
|
56
|
+
lambda { @rules.compile_string("") }.should_not raise_error
|
57
|
+
@rules.weight.should == 0
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should raise an error if compiling a string with bad syntax" do
|
61
|
+
rules = File.read(sample_file("upx.yara")) << "some bogus stuff\n"
|
62
|
+
lambda { @rules.compile_string(rules) }.should raise_error(Yara::CompileError)
|
63
|
+
@rules.weight.should > 0 # it parsed everything up to the error
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise an error if duplicate string data is compiled" do
|
67
|
+
rules = File.read(sample_file("upx.yara"))
|
68
|
+
lambda { @rules.compile_string(rules) }.should_not raise_error
|
69
|
+
lambda { @rules.compile_string(rules) }.should raise_error(Yara::CompileError)
|
70
|
+
@rules.weight.should > 0
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should indicate the current namespace" do
|
74
|
+
@rules.current_namespace.should be_kind_of(String)
|
75
|
+
@rules.current_namespace.should == "default"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should indicate all known namespaces" do
|
79
|
+
@rules.namespaces.should be_kind_of(Array)
|
80
|
+
@rules.namespaces.should == ["default"]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should support setting a new namespace" do
|
84
|
+
@rules.namespaces.should be_kind_of(Array)
|
85
|
+
@rules.namespaces.should == ["default"]
|
86
|
+
|
87
|
+
@rules.set_namespace("a_new_namespace").should == "a_new_namespace"
|
88
|
+
@rules.current_namespace.should == "a_new_namespace"
|
89
|
+
@rules.namespaces.should be_kind_of(Array)
|
90
|
+
@rules.namespaces.should == ["a_new_namespace", "default"]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should not create duplicate namespaces" do
|
94
|
+
@rules.namespaces.should be_kind_of(Array)
|
95
|
+
@rules.namespaces.should == ["default"]
|
96
|
+
|
97
|
+
@rules.set_namespace("a_new_namespace").should == "a_new_namespace"
|
98
|
+
@rules.current_namespace.should == "a_new_namespace"
|
99
|
+
@rules.namespaces.should be_kind_of(Array)
|
100
|
+
@rules.namespaces.should == ["a_new_namespace", "default"]
|
101
|
+
|
102
|
+
@rules.set_namespace("default").should == "default"
|
103
|
+
@rules.current_namespace.should == "default"
|
104
|
+
@rules.namespaces.should == ["a_new_namespace", "default"]
|
105
|
+
|
106
|
+
@rules.set_namespace("a_new_namespace").should == "a_new_namespace"
|
107
|
+
@rules.current_namespace.should == "a_new_namespace"
|
108
|
+
@rules.namespaces.should == ["a_new_namespace", "default"]
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should scan a file" do
|
112
|
+
@rules.compile_file(sample_file("packers.yara"))
|
113
|
+
@rules.weight.should > 0
|
114
|
+
results = @rules.scan_file(sample_file("DumpMem.exe"))
|
115
|
+
results.should be_kind_of(Array)
|
116
|
+
results.size.should == 1
|
117
|
+
m = results.first
|
118
|
+
m.should be_kind_of(Yara::Match)
|
119
|
+
m.should be_frozen
|
120
|
+
|
121
|
+
m.rule.should == "UPX"
|
122
|
+
m.rule.should be_frozen
|
123
|
+
|
124
|
+
m.namespace.should == "default"
|
125
|
+
m.namespace.should be_frozen
|
126
|
+
|
127
|
+
m.tags.should == ["compression", "packer", "shady"]
|
128
|
+
m.tags.should be_frozen
|
129
|
+
m.tags.map{|v| v.should be_frozen }
|
130
|
+
|
131
|
+
strings = m.strings.sort
|
132
|
+
strings.each do |ms|
|
133
|
+
ms.should be_kind_of(Yara::MatchString)
|
134
|
+
ms.identifier.should be_frozen
|
135
|
+
ms.buffer.should be_frozen
|
136
|
+
end
|
137
|
+
|
138
|
+
strings.map{|ms| [ms.offset, ms.identifier, md5(ms.buffer)] }.should == [
|
139
|
+
[2824, "$noep5", "af79592a2fc536596fcbe87409734626"],
|
140
|
+
[2830, "$noep3", "04b044f4bfeb6899b6b60ff7d6b1d103"],
|
141
|
+
[3010, "$noep2", "8711f47b104922246e5733211cd832b1"],
|
142
|
+
[3110, "$noep7", "71be53d1049f47219ad8f26a77255229"],
|
143
|
+
[3157, "$noep8", "b9beede7f0d05ee657501cea72e1a453"]
|
144
|
+
]
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should raise an error if scanning an invalid file" do
|
148
|
+
@rules.compile_file(sample_file("packers.yara"))
|
149
|
+
@rules.weight.should > 0
|
150
|
+
lambda { @rules.scan_file(sample_file("not a real file at all")) }.should raise_error(Yara::ScanError)
|
151
|
+
lambda { @rules.scan_file(Object.new)}.should raise_error(TypeError)
|
152
|
+
lambda { @rules.scan_file(nil)}.should raise_error(TypeError)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should raise an error if scanning a zero-length file" do
|
156
|
+
@rules.compile_file(sample_file("packers.yara"))
|
157
|
+
@rules.weight.should > 0
|
158
|
+
lambda { @rules.scan_file("/dev/null")}.should raise_error(Yara::ScanError)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should scan a string" do
|
162
|
+
@rules.compile_file(sample_file("packers.yara"))
|
163
|
+
@rules.weight.should > 0
|
164
|
+
results = @rules.scan_string(File.read(sample_file("DumpMem.exe")))
|
165
|
+
results.should be_kind_of(Array)
|
166
|
+
results.size.should == 1
|
167
|
+
m = results.first
|
168
|
+
m.should be_kind_of(Yara::Match)
|
169
|
+
m.should be_frozen
|
170
|
+
|
171
|
+
m.rule.should == "UPX"
|
172
|
+
m.rule.should be_frozen
|
173
|
+
|
174
|
+
m.namespace.should == "default"
|
175
|
+
m.namespace.should be_frozen
|
176
|
+
|
177
|
+
m.tags.should == ["compression", "packer", "shady"]
|
178
|
+
m.tags.should be_frozen
|
179
|
+
m.tags.map{|v| v.should be_frozen }
|
180
|
+
|
181
|
+
m.strings.should be_frozen
|
182
|
+
strings = m.strings.sort
|
183
|
+
strings.each do |ms|
|
184
|
+
ms.should be_kind_of(Yara::MatchString)
|
185
|
+
ms.identifier.should be_frozen
|
186
|
+
ms.buffer.should be_frozen
|
187
|
+
end
|
188
|
+
|
189
|
+
strings.map{|ms| [ms.offset, ms.identifier, md5(ms.buffer)] }.should == [
|
190
|
+
[2824, "$noep5", "af79592a2fc536596fcbe87409734626"],
|
191
|
+
[2830, "$noep3", "04b044f4bfeb6899b6b60ff7d6b1d103"],
|
192
|
+
[3010, "$noep2", "8711f47b104922246e5733211cd832b1"],
|
193
|
+
[3110, "$noep7", "71be53d1049f47219ad8f26a77255229"],
|
194
|
+
[3157, "$noep8", "b9beede7f0d05ee657501cea72e1a453"]
|
195
|
+
]
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should raise an error if scanning an invalid string" do
|
200
|
+
@rules.compile_file(sample_file("packers.yara"))
|
201
|
+
@rules.weight.should > 0
|
202
|
+
lambda { @rules.scan_string(Object.new)}.should raise_error(TypeError)
|
203
|
+
lambda { @rules.scan_string(nil)}.should raise_error(TypeError)
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
Binary file
|