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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77c78c082eac821fd90e99808b1d944d7ac5e0a4c597339d46e9d9806cc61a17
4
- data.tar.gz: 75a6e4cb0f1d9b6b89d611bfd615006b5f638532337a8a6b03d5e37bd697a6a5
3
+ metadata.gz: 814d5fa21cda6f98707e038549321eab8ce359f013c47d36e8d0845c05ff0b2c
4
+ data.tar.gz: 531d85f217da5f9bec89de9319ee5f9f33c3a801ec75db439de1fa377612c88e
5
5
  SHA512:
6
- metadata.gz: de69cea095663dc7a7fe66d896d846139328f3e0e47d07c3ad05340e9f99ee755311da3ec6ab1afc19ddda809fea1de04274fecf4404544c0e7ed48bde48e3de
7
- data.tar.gz: c09131210c41e871d677b0779f2a736dad22c6ba1c32d3e155f1083bb4886b3d6d0815c293889a8da497b3af882fad5fb31d234c46733243cefc576c023ee964
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.0.0)
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.0)
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.14
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
- TODO: Write usage instructions here
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, # message
89
- :pointer, # message_data_pointer
90
- :pointer, # user_data_pointer
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
- :string, # buffer (aka test subject)
108
+ :pointer, # buffer (aka test subject)
104
109
  :size_t, # buffer size (String#bytesize)
105
110
  :int, # flags
106
111
  :scan_callback, # proc
@@ -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
- RULE_IDENTIFIER = 1
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, rule_ptr)
16
+ def initialize(callback_type, rule, user_data)
18
17
  @callback_type = callback_type
19
- @rule = YrRule.new(rule_ptr)
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.values[RULE_IDENTIFIER]
27
+ @rule[:identifier]
28
+ end
29
+
30
+ def scan_complete?
31
+ callback_type == SCAN_FINISHED
24
32
  end
25
33
 
26
- def rule_meta
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.values[METAS_IDENTIFIER]
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.values.last
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 scan_complete?
45
- callback_type == SCAN_FINISHED
46
- end
47
-
48
- def rule_outcome?
49
- [RULE_MATCHING, RULE_NOT_MATCHING].include?(callback_type)
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 match?
53
- callback_type == RULE_MATCHING
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
- private
57
-
58
- def meta_as_hash(meta)
59
- name, string_value, int_value, type, _flags = meta.values
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)
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yara
4
- VERSION = "2.0.0"
4
+ VERSION = "3.0.0"
5
5
  end
data/lib/yara/yr_rule.rb CHANGED
@@ -5,7 +5,7 @@ module Yara
5
5
  :identifier, :string,
6
6
  :tags, :string,
7
7
  :metas, :pointer,
8
- :strings, YrString.ptr,
8
+ :strings, :pointer,
9
9
  :ns, YrNamespace.ptr
10
10
  end
11
11
  end
@@ -1,5 +1,15 @@
1
1
  module Yara
2
2
  class YrString < FFI::Struct
3
- layout :identifier, :string
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
- SCAN_FINISHED = 3
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
- compiler_pointer = ::FFI::MemoryPointer.new(:pointer)
22
- Yara::FFI.yr_compiler_create(compiler_pointer)
23
- compiler_pointer = compiler_pointer.get_pointer(0)
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
- results
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
- Yara::FFI.yr_finalize
26
+ scanner.close
27
+ stop
63
28
  end
64
29
  end
data/script/bootstrap ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ docker build . -t yara-ffi
data/script/test ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ docker run -it --mount type=bind,src="$(pwd)",dst=/app yara-ffi bundle exec rake
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: 2.0.0
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-08-24 00:00:00.000000000 Z
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
- - vendor/cache/ast-2.4.2.gem
56
- - vendor/cache/coderay-1.1.3.gem
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:
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file