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 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