yara-ffi 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|