yara-ffi 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +17 -0
- data/Gemfile.lock +3 -3
- data/README.md +28 -1
- data/lib/yara/ffi.rb +9 -4
- data/lib/yara/scan_result.rb +51 -23
- data/lib/yara/scanner.rb +81 -0
- data/lib/yara/version.rb +1 -1
- data/lib/yara/yr_rule.rb +1 -1
- data/lib/yara/yr_string.rb +11 -1
- data/lib/yara.rb +14 -49
- data/script/bootstrap +3 -0
- data/script/test +3 -0
- metadata +6 -18
- data/vendor/cache/ast-2.4.2.gem +0 -0
- data/vendor/cache/coderay-1.1.3.gem +0 -0
- data/vendor/cache/ffi-1.15.0.gem +0 -0
- data/vendor/cache/method_source-1.0.0.gem +0 -0
- data/vendor/cache/minitest-5.14.4.gem +0 -0
- data/vendor/cache/parallel-1.20.1.gem +0 -0
- data/vendor/cache/parser-3.0.0.0.gem +0 -0
- data/vendor/cache/pry-0.14.0.gem +0 -0
- data/vendor/cache/rainbow-3.0.0.gem +0 -0
- data/vendor/cache/rake-13.0.3.gem +0 -0
- data/vendor/cache/regexp_parser-2.1.1.gem +0 -0
- data/vendor/cache/rexml-3.2.4.gem +0 -0
- data/vendor/cache/rubocop-1.11.0.gem +0 -0
- data/vendor/cache/rubocop-ast-1.4.1.gem +0 -0
- data/vendor/cache/ruby-progressbar-1.11.0.gem +0 -0
- data/vendor/cache/unicode-display_width-2.0.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 814d5fa21cda6f98707e038549321eab8ce359f013c47d36e8d0845c05ff0b2c
|
4
|
+
data.tar.gz: 531d85f217da5f9bec89de9319ee5f9f33c3a801ec75db439de1fa377612c88e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fd910b4f3ea435dcc5cfaa1763fe7cd33727bc77929b52d326d4f3baaad7caff2671c73100ec5102bdb61f9ac34d330ad2a33626faaeebf65ff16dde7d7e6fe
|
7
|
+
data.tar.gz: 53133f057a23dc32227a6c603322cdd5b9da273416bdd6aad9245b4c270249c83dd8e8f5211f531be1180a12c28825824977966425456bd9c18ff8883566f7bb
|
data/Dockerfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
FROM ruby:2.6.6
|
2
|
+
|
3
|
+
RUN apt-get update -qq
|
4
|
+
RUN apt-get install -y flex bison
|
5
|
+
|
6
|
+
WORKDIR /app
|
7
|
+
|
8
|
+
COPY . ./
|
9
|
+
RUN gem install bundler:2.2.15
|
10
|
+
RUN bundle install
|
11
|
+
|
12
|
+
RUN git clone --recursive --branch v4.1.1 https://github.com/VirusTotal/yara.git /tmp/yara && \
|
13
|
+
cd /tmp/yara/ && \
|
14
|
+
./bootstrap.sh && \
|
15
|
+
./configure && \
|
16
|
+
make && \
|
17
|
+
make install
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
yara-ffi (1.
|
4
|
+
yara-ffi (2.1.1)
|
5
5
|
ffi
|
6
6
|
|
7
7
|
GEM
|
@@ -9,7 +9,7 @@ GEM
|
|
9
9
|
specs:
|
10
10
|
ast (2.4.2)
|
11
11
|
coderay (1.1.3)
|
12
|
-
ffi (1.15.
|
12
|
+
ffi (1.15.4)
|
13
13
|
method_source (1.0.0)
|
14
14
|
minitest (5.14.4)
|
15
15
|
parallel (1.20.1)
|
@@ -48,4 +48,4 @@ DEPENDENCIES
|
|
48
48
|
yara-ffi!
|
49
49
|
|
50
50
|
BUNDLED WITH
|
51
|
-
2.2.
|
51
|
+
2.2.15
|
data/README.md
CHANGED
@@ -20,7 +20,34 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
|
23
|
+
```ruby
|
24
|
+
Yara.start # run before you start using the Yara API.
|
25
|
+
|
26
|
+
rule = <<-RULE
|
27
|
+
rule ExampleRule
|
28
|
+
{
|
29
|
+
meta:
|
30
|
+
string_meta = "an example rule for testing"
|
31
|
+
|
32
|
+
strings:
|
33
|
+
$my_text_string = "we were here"
|
34
|
+
$my_text_regex = /were here/
|
35
|
+
|
36
|
+
condition:
|
37
|
+
$my_text_string or $my_text_regex
|
38
|
+
}
|
39
|
+
RULE
|
40
|
+
|
41
|
+
scanner = Yara::Scanner.new
|
42
|
+
scanner.add_rule(rule)
|
43
|
+
scanner.compile
|
44
|
+
result = scanner.call("one day we were here and then we were not")
|
45
|
+
result.match?
|
46
|
+
# => true
|
47
|
+
|
48
|
+
scanner.close # run when you are done using the scanner API and want to free up memory.
|
49
|
+
Yara.stop # run when you are completely done using the Yara API to free up memory.
|
50
|
+
```
|
24
51
|
|
25
52
|
## Development
|
26
53
|
|
data/lib/yara/ffi.rb
CHANGED
@@ -35,6 +35,11 @@ module Yara
|
|
35
35
|
:pointer, # compiler_pointer
|
36
36
|
], :void
|
37
37
|
|
38
|
+
# int yr_rules_destroy(YR_RULES* rules)
|
39
|
+
attach_function :yr_rules_destroy, [
|
40
|
+
:pointer, # rules_pointer
|
41
|
+
], :void
|
42
|
+
|
38
43
|
# void callback_function(
|
39
44
|
# int error_level,
|
40
45
|
# const char* file_name,
|
@@ -85,9 +90,9 @@ module Yara
|
|
85
90
|
# void* user_data)
|
86
91
|
callback :scan_callback, [
|
87
92
|
:pointer, # YR_SCAN_CONTEXT*
|
88
|
-
:int, #
|
89
|
-
|
90
|
-
|
93
|
+
:int, # callback_type
|
94
|
+
YrRule.ptr, # rule
|
95
|
+
UserData.ptr, # user_data
|
91
96
|
], :int
|
92
97
|
|
93
98
|
# int yr_rules_scan_mem(
|
@@ -100,7 +105,7 @@ module Yara
|
|
100
105
|
# int timeout)
|
101
106
|
attach_function :yr_rules_scan_mem, [
|
102
107
|
:pointer, # rules_pointer*
|
103
|
-
:
|
108
|
+
:pointer, # buffer (aka test subject)
|
104
109
|
:size_t, # buffer size (String#bytesize)
|
105
110
|
:int, # flags
|
106
111
|
:scan_callback, # proc
|
data/lib/yara/scan_result.rb
CHANGED
@@ -6,32 +6,50 @@ module Yara
|
|
6
6
|
META_FLAGS_LAST_IN_RULE = 1
|
7
7
|
|
8
8
|
META_TYPE_INTEGER = 1
|
9
|
-
META_TYPE_STRING = 2
|
9
|
+
# META_TYPE_STRING = 2
|
10
10
|
META_TYPE_BOOLEAN = 3
|
11
11
|
|
12
|
-
|
13
|
-
METAS_IDENTIFIER = 3
|
12
|
+
STRING_FLAGS_LAST_IN_RULE = 0
|
14
13
|
|
15
14
|
attr_reader :callback_type, :rule
|
16
15
|
|
17
|
-
def initialize(callback_type,
|
16
|
+
def initialize(callback_type, rule, user_data)
|
18
17
|
@callback_type = callback_type
|
19
|
-
@rule =
|
18
|
+
@rule = rule
|
19
|
+
@rule_meta = extract_rule_meta
|
20
|
+
@rule_strings = extract_rule_strings
|
21
|
+
@user_data_number = user_data[:number]
|
20
22
|
end
|
21
23
|
|
24
|
+
attr_reader :rule_meta, :rule_strings, :user_data_number
|
25
|
+
|
22
26
|
def rule_name
|
23
|
-
@rule
|
27
|
+
@rule[:identifier]
|
28
|
+
end
|
29
|
+
|
30
|
+
def scan_complete?
|
31
|
+
callback_type == SCAN_FINISHED
|
24
32
|
end
|
25
33
|
|
26
|
-
def
|
34
|
+
def rule_outcome?
|
35
|
+
[RULE_MATCHING, RULE_NOT_MATCHING].include?(callback_type)
|
36
|
+
end
|
37
|
+
|
38
|
+
def match?
|
39
|
+
callback_type == RULE_MATCHING
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def extract_rule_meta
|
27
45
|
metas = {}
|
28
46
|
reading_metas = true
|
29
47
|
meta_index = 0
|
30
|
-
meta_pointer = @rule
|
48
|
+
meta_pointer = @rule[:metas]
|
31
49
|
while reading_metas do
|
32
50
|
meta = YrMeta.new(meta_pointer + meta_index * YrMeta.size)
|
33
51
|
metas.merge!(meta_as_hash(meta))
|
34
|
-
flags = meta
|
52
|
+
flags = meta[:flags]
|
35
53
|
if flags == META_FLAGS_LAST_IN_RULE
|
36
54
|
reading_metas = false
|
37
55
|
else
|
@@ -41,24 +59,34 @@ module Yara
|
|
41
59
|
metas
|
42
60
|
end
|
43
61
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
def extract_rule_strings
|
63
|
+
strings = {}
|
64
|
+
reading_strings = true
|
65
|
+
string_index = 0
|
66
|
+
string_pointer = @rule[:strings]
|
67
|
+
while reading_strings do
|
68
|
+
string = YrString.new(string_pointer + string_index * YrString.size)
|
69
|
+
string_length = string[:length]
|
70
|
+
flags = string[:flags]
|
71
|
+
if flags == STRING_FLAGS_LAST_IN_RULE
|
72
|
+
reading_strings = false
|
73
|
+
else
|
74
|
+
strings.merge!(string_as_hash(string)) unless string_length == 0
|
75
|
+
string_index += 1
|
76
|
+
end
|
77
|
+
end
|
78
|
+
strings
|
50
79
|
end
|
51
80
|
|
52
|
-
def
|
53
|
-
|
81
|
+
def meta_as_hash(meta)
|
82
|
+
value = meta_value(meta[:string], meta[:integer], meta[:type])
|
83
|
+
{ meta[:identifier].to_sym => value }
|
54
84
|
end
|
55
85
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
value = meta_value(string_value, int_value, type)
|
61
|
-
{ name.to_sym => value }
|
86
|
+
def string_as_hash(yr_string)
|
87
|
+
string_pointer = yr_string[:string]
|
88
|
+
string_identifier = yr_string[:identifier]
|
89
|
+
{ string_identifier.to_sym => string_pointer.read_string }
|
62
90
|
end
|
63
91
|
|
64
92
|
def meta_value(string_value, int_value, type)
|
data/lib/yara/scanner.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
module Yara
|
2
|
+
class Scanner
|
3
|
+
class NotCompiledError < StandardError; end
|
4
|
+
|
5
|
+
ERROR_CALLBACK = proc do |error_level, file_name, line_number, rule, message, user_data|
|
6
|
+
# noop
|
7
|
+
end
|
8
|
+
|
9
|
+
SCAN_FINISHED = 3
|
10
|
+
|
11
|
+
# Public: Initializes instance of scanner. Under the hood this calls yr_initialize, then
|
12
|
+
# creates a pointer, then calls yr_compiler_create with that pointer.
|
13
|
+
#
|
14
|
+
# error_callback: (optional) Proc to be called when an error occurs.
|
15
|
+
# user_data: (optional) Instance of UserData to store and pass information.
|
16
|
+
def initialize(error_callback: ERROR_CALLBACK, user_data: UserData.new)
|
17
|
+
@error_callback = error_callback
|
18
|
+
@user_data = user_data
|
19
|
+
@compiler_pointer = ::FFI::MemoryPointer.new(:pointer)
|
20
|
+
Yara::FFI.yr_compiler_create(@compiler_pointer)
|
21
|
+
@compiler_pointer = @compiler_pointer.get_pointer(0)
|
22
|
+
Yara::FFI.yr_compiler_set_callback(@compiler_pointer, error_callback, user_data)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: Adds a rule to the scanner and returns the namespace value. If a namespace
|
26
|
+
# is not provided it will default to nil and use the global namespace.
|
27
|
+
#
|
28
|
+
# rule_string - String containing the Yara rule to be added.
|
29
|
+
# namespace: (optional) String containing the namespace to be used for the rule.
|
30
|
+
def add_rule(rule_string, namespace: nil)
|
31
|
+
Yara::FFI.yr_compiler_add_string(@compiler_pointer, rule_string, namespace)
|
32
|
+
end
|
33
|
+
|
34
|
+
def compile
|
35
|
+
@rules_pointer = ::FFI::MemoryPointer.new(:pointer)
|
36
|
+
Yara::FFI.yr_compiler_get_rules(@compiler_pointer, @rules_pointer)
|
37
|
+
@rules_pointer = @rules_pointer.get_pointer(0)
|
38
|
+
Yara::FFI.yr_compiler_destroy(@compiler_pointer)
|
39
|
+
end
|
40
|
+
|
41
|
+
def call(test_string)
|
42
|
+
raise NotCompiledError unless @rules_pointer
|
43
|
+
|
44
|
+
results = []
|
45
|
+
scanning = true
|
46
|
+
result_callback = proc do |context_ptr, callback_type, rule, user_data|
|
47
|
+
if callback_type == SCAN_FINISHED
|
48
|
+
scanning = false
|
49
|
+
else
|
50
|
+
result = ScanResult.new(callback_type, rule, user_data)
|
51
|
+
results << result if result.rule_outcome?
|
52
|
+
end
|
53
|
+
|
54
|
+
0 # ERROR_SUCCESS
|
55
|
+
end
|
56
|
+
|
57
|
+
test_string_bytesize = test_string.bytesize
|
58
|
+
test_string_pointer = ::FFI::MemoryPointer.new(:char, test_string_bytesize)
|
59
|
+
test_string_pointer.put_bytes(0, test_string)
|
60
|
+
|
61
|
+
Yara::FFI.yr_rules_scan_mem(
|
62
|
+
@rules_pointer,
|
63
|
+
test_string_pointer,
|
64
|
+
test_string_bytesize,
|
65
|
+
0,
|
66
|
+
result_callback,
|
67
|
+
@user_data,
|
68
|
+
1,
|
69
|
+
)
|
70
|
+
|
71
|
+
while scanning do
|
72
|
+
end
|
73
|
+
|
74
|
+
results
|
75
|
+
end
|
76
|
+
|
77
|
+
def close
|
78
|
+
Yara::FFI.yr_rules_destroy(@rules_pointer)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/yara/version.rb
CHANGED
data/lib/yara/yr_rule.rb
CHANGED
data/lib/yara/yr_string.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
module Yara
|
2
2
|
class YrString < FFI::Struct
|
3
|
-
layout
|
3
|
+
layout \
|
4
|
+
:flags, :uint32_t,
|
5
|
+
:idx, :uint32_t,
|
6
|
+
:fixed_offset, :int64_t,
|
7
|
+
:rule_idx, :uint32_t,
|
8
|
+
:length, :int32_t,
|
9
|
+
:string, :pointer,
|
10
|
+
:chained_to, :pointer,
|
11
|
+
:chain_gap_min, :int32_t,
|
12
|
+
:chain_gap_max, :int32_t,
|
13
|
+
:identifier, :string
|
4
14
|
end
|
5
15
|
end
|
data/lib/yara.rb
CHANGED
@@ -4,61 +4,26 @@ require "ffi"
|
|
4
4
|
require "pry"
|
5
5
|
require_relative "yara/ffi"
|
6
6
|
require_relative "yara/scan_result"
|
7
|
+
require_relative "yara/scanner"
|
7
8
|
require_relative "yara/version"
|
8
9
|
|
9
10
|
module Yara
|
10
|
-
|
11
|
-
|
12
|
-
class Error < StandardError; end
|
13
|
-
|
14
|
-
def self.test(rule_string, test_string)
|
15
|
-
user_data = UserData.new
|
16
|
-
scanning = true
|
17
|
-
results = []
|
18
|
-
|
11
|
+
def self.start
|
19
12
|
Yara::FFI.yr_initialize
|
13
|
+
end
|
20
14
|
|
21
|
-
|
22
|
-
Yara::FFI.
|
23
|
-
|
24
|
-
|
25
|
-
error_callback = proc do |error_level, file_name, line_number, rule, message, user_data|
|
26
|
-
# noop
|
27
|
-
end
|
28
|
-
|
29
|
-
Yara::FFI.yr_compiler_set_callback(compiler_pointer, error_callback, user_data)
|
30
|
-
Yara::FFI.yr_compiler_add_string(compiler_pointer, rule_string, nil)
|
31
|
-
|
32
|
-
rules_pointer =::FFI::MemoryPointer.new(:pointer)
|
33
|
-
Yara::FFI.yr_compiler_get_rules(compiler_pointer, rules_pointer)
|
34
|
-
rules_pointer = rules_pointer.get_pointer(0)
|
35
|
-
|
36
|
-
result_callback = proc do |context_ptr, callback_type, rule_ptr, user_data_ptr|
|
37
|
-
if callback_type == SCAN_FINISHED
|
38
|
-
scanning = false
|
39
|
-
else
|
40
|
-
result = ScanResult.new(callback_type, rule_ptr)
|
41
|
-
results << result if result.rule_outcome?
|
42
|
-
end
|
43
|
-
|
44
|
-
0 # ERROR_SUCCESS
|
45
|
-
end
|
46
|
-
|
47
|
-
Yara::FFI.yr_rules_scan_mem(
|
48
|
-
rules_pointer,
|
49
|
-
test_string,
|
50
|
-
test_string.bytesize,
|
51
|
-
0,
|
52
|
-
result_callback,
|
53
|
-
user_data,
|
54
|
-
1,
|
55
|
-
)
|
56
|
-
|
57
|
-
while scanning do
|
58
|
-
end
|
15
|
+
def self.stop
|
16
|
+
Yara::FFI.yr_finalize
|
17
|
+
end
|
59
18
|
|
60
|
-
|
19
|
+
def self.test(rule_string, test_string)
|
20
|
+
start
|
21
|
+
scanner = Yara::Scanner.new
|
22
|
+
scanner.add_rule(rule_string)
|
23
|
+
scanner.compile
|
24
|
+
scanner.call(test_string)
|
61
25
|
ensure
|
62
|
-
|
26
|
+
scanner.close
|
27
|
+
stop
|
63
28
|
end
|
64
29
|
end
|
data/script/bootstrap
ADDED
data/script/test
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yara-ffi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Hoyt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- ".rubocop.yml"
|
37
37
|
- CHANGELOG.md
|
38
38
|
- CODE_OF_CONDUCT.md
|
39
|
+
- Dockerfile
|
39
40
|
- Gemfile
|
40
41
|
- Gemfile.lock
|
41
42
|
- LICENSE.txt
|
@@ -46,28 +47,15 @@ files:
|
|
46
47
|
- lib/yara.rb
|
47
48
|
- lib/yara/ffi.rb
|
48
49
|
- lib/yara/scan_result.rb
|
50
|
+
- lib/yara/scanner.rb
|
49
51
|
- lib/yara/user_data.rb
|
50
52
|
- lib/yara/version.rb
|
51
53
|
- lib/yara/yr_meta.rb
|
52
54
|
- lib/yara/yr_namespace.rb
|
53
55
|
- lib/yara/yr_rule.rb
|
54
56
|
- lib/yara/yr_string.rb
|
55
|
-
-
|
56
|
-
-
|
57
|
-
- vendor/cache/ffi-1.15.0.gem
|
58
|
-
- vendor/cache/method_source-1.0.0.gem
|
59
|
-
- vendor/cache/minitest-5.14.4.gem
|
60
|
-
- vendor/cache/parallel-1.20.1.gem
|
61
|
-
- vendor/cache/parser-3.0.0.0.gem
|
62
|
-
- vendor/cache/pry-0.14.0.gem
|
63
|
-
- vendor/cache/rainbow-3.0.0.gem
|
64
|
-
- vendor/cache/rake-13.0.3.gem
|
65
|
-
- vendor/cache/regexp_parser-2.1.1.gem
|
66
|
-
- vendor/cache/rexml-3.2.4.gem
|
67
|
-
- vendor/cache/rubocop-1.11.0.gem
|
68
|
-
- vendor/cache/rubocop-ast-1.4.1.gem
|
69
|
-
- vendor/cache/ruby-progressbar-1.11.0.gem
|
70
|
-
- vendor/cache/unicode-display_width-2.0.0.gem
|
57
|
+
- script/bootstrap
|
58
|
+
- script/test
|
71
59
|
- yara-ffi.gemspec
|
72
60
|
homepage: https://github.com/jonmagic/yara-ffi
|
73
61
|
licenses:
|
data/vendor/cache/ast-2.4.2.gem
DELETED
Binary file
|
Binary file
|
data/vendor/cache/ffi-1.15.0.gem
DELETED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/vendor/cache/pry-0.14.0.gem
DELETED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|