yara-ffi 2.1.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69d13f5f4b62199af83b30a5bb43366c98bd298b10f11b33d54ce931b5b3a23b
4
- data.tar.gz: 384f0506d4781049c57f143243b4b8ff9fb7c46fc95cd8e9fe781d39e16c22ce
3
+ metadata.gz: 8093d210271e152cfd1d66f69169f9efaf46838ad93dd5473a0b11a242bc0164
4
+ data.tar.gz: a73687b9d7a3e7d098d4706c7c558954f1963a8bf8b3206984cdccd8dd757d2d
5
5
  SHA512:
6
- metadata.gz: 6811bee54889a6a95a01df893fe694e3fc2bd1a424063c7d51aa222f6a37e7b202dbcee06ed58b7768b9b348b530918b3e093994ac753831823951ac194a21cd
7
- data.tar.gz: b58b0fa59f64501b560f99b012ea2132617e16811988e70d887838df157028fabdeed2109ba723389e1830e411c111233f1f0a1ef6e877913ac55849d37203dc
6
+ metadata.gz: 879454866631eb296874a07aed2848a3252d547b45b593245114a0bb57404b5bea0badfecb553f77bd0029727112bfd9cde527f8722c3dfcf55e73f16a0cb6f7
7
+ data.tar.gz: 6cc31a9d0e330897c3133fd17d90ddac3e7b54a1b073af31235185e3e70a2738fa8041e9adc8c087e5867d34dc4ffaed3f75c7c54d4be08bdfe60059d5c0e672
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 (3.0.0)
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.5)
13
13
  method_source (1.0.0)
14
14
  minitest (5.14.4)
15
15
  parallel (1.20.1)
@@ -37,6 +37,8 @@ GEM
37
37
  unicode-display_width (2.0.0)
38
38
 
39
39
  PLATFORMS
40
+ aarch64-linux
41
+ arm64-darwin-21
40
42
  x86_64-darwin-19
41
43
  x86_64-linux
42
44
 
@@ -48,4 +50,4 @@ DEPENDENCIES
48
50
  yara-ffi!
49
51
 
50
52
  BUNDLED WITH
51
- 2.2.14
53
+ 2.2.32
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").first
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(
@@ -6,38 +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
12
  STRING_FLAGS_LAST_IN_RULE = 0
13
13
 
14
- STRING_LENGTH = 4
15
- STRING_POINTER = 5
16
-
17
- RULE_IDENTIFIER = 1
18
- METAS_IDENTIFIER = 3
19
- STRING_IDENTIFIER = 4
20
-
21
14
  attr_reader :callback_type, :rule
22
15
 
23
- def initialize(callback_type, rule_ptr)
16
+ def initialize(callback_type, rule, user_data)
24
17
  @callback_type = callback_type
25
- @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]
26
22
  end
27
23
 
24
+ attr_reader :rule_meta, :rule_strings, :user_data_number
25
+
28
26
  def rule_name
29
- @rule.values[RULE_IDENTIFIER]
27
+ @rule[:identifier]
28
+ end
29
+
30
+ def scan_complete?
31
+ callback_type == SCAN_FINISHED
32
+ end
33
+
34
+ def rule_outcome?
35
+ [RULE_MATCHING, RULE_NOT_MATCHING].include?(callback_type)
36
+ end
37
+
38
+ def match?
39
+ callback_type == RULE_MATCHING
30
40
  end
31
41
 
32
- def rule_meta
42
+ private
43
+
44
+ def extract_rule_meta
33
45
  metas = {}
34
46
  reading_metas = true
35
47
  meta_index = 0
36
- meta_pointer = @rule.values[METAS_IDENTIFIER]
48
+ meta_pointer = @rule[:metas]
37
49
  while reading_metas do
38
50
  meta = YrMeta.new(meta_pointer + meta_index * YrMeta.size)
39
51
  metas.merge!(meta_as_hash(meta))
40
- flags = meta.values.last
52
+ flags = meta[:flags]
41
53
  if flags == META_FLAGS_LAST_IN_RULE
42
54
  reading_metas = false
43
55
  else
@@ -47,15 +59,15 @@ module Yara
47
59
  metas
48
60
  end
49
61
 
50
- def rule_strings
62
+ def extract_rule_strings
51
63
  strings = {}
52
64
  reading_strings = true
53
65
  string_index = 0
54
- string_pointer = @rule.values[STRING_IDENTIFIER]
66
+ string_pointer = @rule[:strings]
55
67
  while reading_strings do
56
68
  string = YrString.new(string_pointer + string_index * YrString.size)
57
- string_length = string.values[STRING_LENGTH]
58
- flags = string.values.first
69
+ string_length = string[:length]
70
+ flags = string[:flags]
59
71
  if flags == STRING_FLAGS_LAST_IN_RULE
60
72
  reading_strings = false
61
73
  else
@@ -66,29 +78,14 @@ module Yara
66
78
  strings
67
79
  end
68
80
 
69
- def scan_complete?
70
- callback_type == SCAN_FINISHED
71
- end
72
-
73
- def rule_outcome?
74
- [RULE_MATCHING, RULE_NOT_MATCHING].include?(callback_type)
75
- end
76
-
77
- def match?
78
- callback_type == RULE_MATCHING
79
- end
80
-
81
- private
82
-
83
81
  def meta_as_hash(meta)
84
- name, string_value, int_value, type, _flags = meta.values
85
- value = meta_value(string_value, int_value, type)
86
- { name.to_sym => value }
82
+ value = meta_value(meta[:string], meta[:integer], meta[:type])
83
+ { meta[:identifier].to_sym => value }
87
84
  end
88
85
 
89
86
  def string_as_hash(yr_string)
90
- string_pointer = yr_string.values[STRING_POINTER]
91
- string_identifier = yr_string.values.last
87
+ string_pointer = yr_string[:string]
88
+ string_identifier = yr_string[:identifier]
92
89
  { string_identifier.to_sym => string_pointer.read_string }
93
90
  end
94
91
 
@@ -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 creates a pointer,
12
+ # 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
@@ -1,5 +1,5 @@
1
1
  module Yara
2
2
  class UserData < FFI::Struct
3
- layout :number, :int32
3
+ layout :number, :int
4
4
  end
5
5
  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.1.0"
4
+ VERSION = "3.1.0"
5
5
  end
data/lib/yara/yr_meta.rb CHANGED
@@ -3,8 +3,8 @@ module Yara
3
3
  layout \
4
4
  :identifier, :string,
5
5
  :string, :string,
6
- :integer, :int64_t,
7
- :type, :int32_t,
8
- :flags, :int32_t
6
+ :integer, :ulong_long,
7
+ :type, :int,
8
+ :flags, :int
9
9
  end
10
10
  end
data/lib/yara/yr_rule.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Yara
2
2
  class YrRule < FFI::Struct
3
3
  layout \
4
- :flags, :int32_t,
4
+ :flags, :int,
5
5
  :identifier, :string,
6
6
  :tags, :string,
7
7
  :metas, :pointer,
@@ -1,15 +1,15 @@
1
1
  module Yara
2
2
  class YrString < FFI::Struct
3
3
  layout \
4
- :flags, :uint32_t,
5
- :idx, :uint32_t,
6
- :fixed_offset, :int64_t,
7
- :rule_idx, :uint32_t,
8
- :length, :int32_t,
4
+ :flags, :uint,
5
+ :idx, :uint,
6
+ :fixed_offset, :ulong_long,
7
+ :rule_idx, :uint,
8
+ :length, :uint,
9
9
  :string, :pointer,
10
10
  :chained_to, :pointer,
11
- :chain_gap_min, :int32_t,
12
- :chain_gap_max, :int32_t,
11
+ :chain_gap_min, :uint,
12
+ :chain_gap_max, :uint,
13
13
  :identifier, :string
14
14
  end
15
15
  end
data/lib/yara.rb CHANGED
@@ -4,65 +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
- test_string_bytesize = test_string.bytesize
48
- test_string_pointer = ::FFI::MemoryPointer.new(:char, test_string_bytesize)
49
- test_string_pointer.put_bytes(0, test_string)
50
-
51
- Yara::FFI.yr_rules_scan_mem(
52
- rules_pointer,
53
- test_string_pointer,
54
- test_string_bytesize,
55
- 0,
56
- result_callback,
57
- user_data,
58
- 1,
59
- )
60
-
61
- while scanning do
62
- end
15
+ def self.stop
16
+ Yara::FFI.yr_finalize
17
+ end
63
18
 
64
- 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)
65
25
  ensure
66
- Yara::FFI.yr_finalize
26
+ scanner.close
27
+ stop
67
28
  end
68
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.1.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Hoyt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-30 00:00:00.000000000 Z
11
+ date: 2022-04-18 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:
@@ -76,7 +64,7 @@ metadata:
76
64
  homepage_uri: https://github.com/jonmagic/yara-ffi
77
65
  source_code_uri: https://github.com/jonmagic/yara-ffi
78
66
  changelog_uri: https://github.com/jonmagic/yara-ffi/main/CHANGELOG.md,
79
- post_install_message:
67
+ post_install_message:
80
68
  rdoc_options: []
81
69
  require_paths:
82
70
  - lib
@@ -91,8 +79,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
79
  - !ruby/object:Gem::Version
92
80
  version: '0'
93
81
  requirements: []
94
- rubygems_version: 3.0.3
95
- signing_key:
82
+ rubygems_version: 3.3.3
83
+ signing_key:
96
84
  specification_version: 4
97
85
  summary: A Ruby API to libyara.
98
86
  test_files: []
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