yara-ffi 3.1.0 → 4.1.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.
@@ -0,0 +1,178 @@
1
+ module Yara
2
+ # Public: Represents a single pattern match found during YARA scanning.
3
+ #
4
+ # A PatternMatch contains detailed information about where and how a specific
5
+ # YARA pattern matched within the scanned data. This includes the exact offset
6
+ # and length of the match, allowing for precise forensic analysis and data
7
+ # extraction.
8
+ #
9
+ # PatternMatch instances are typically created internally during the scanning
10
+ # process and accessed through ScanResult methods like pattern_matches.
11
+ #
12
+ # Examples
13
+ #
14
+ # # Access pattern matches through scan results
15
+ # results.each do |result|
16
+ # result.pattern_matches.each do |pattern_name, matches|
17
+ # matches.each do |match|
18
+ # puts "Pattern #{pattern_name} matched at offset #{match.offset}"
19
+ # puts "Matched text: '#{match.matched_data(scanned_data)}'"
20
+ # end
21
+ # end
22
+ # end
23
+ class PatternMatch
24
+ # Public: The byte offset where this pattern match begins in the scanned data.
25
+ attr_reader :offset
26
+
27
+ # Public: The length in bytes of this pattern match.
28
+ attr_reader :length
29
+
30
+ # Public: Initialize a new PatternMatch.
31
+ #
32
+ # This constructor is typically called internally when processing YARA-X
33
+ # match results. It captures the precise location and size of a pattern
34
+ # match within scanned data.
35
+ #
36
+ # offset - An Integer byte offset where the match begins
37
+ # length - An Integer length in bytes of the match
38
+ #
39
+ # Examples
40
+ #
41
+ # # Typically created internally during scanning
42
+ # match = PatternMatch.new(42, 10)
43
+ # match.offset # => 42
44
+ # match.length # => 10
45
+ def initialize(offset, length)
46
+ @offset = offset
47
+ @length = length
48
+ end
49
+
50
+ # Public: Extract the actual matched data from the scanned content.
51
+ #
52
+ # This method returns the exact bytes that matched the pattern by extracting
53
+ # the appropriate slice from the original scanned data. This is useful for
54
+ # forensic analysis, debugging rules, and understanding what triggered a match.
55
+ #
56
+ # data - A String containing the original data that was scanned
57
+ #
58
+ # Examples
59
+ #
60
+ # # Extract what actually matched
61
+ # scan_data = "hello world test data"
62
+ # match = PatternMatch.new(6, 5) # matches "world"
63
+ # match.matched_data(scan_data) # => "world"
64
+ #
65
+ # Returns a String containing the matched bytes.
66
+ # Returns empty String if offset/length are outside data bounds.
67
+ def matched_data(data)
68
+ return "" if offset < 0 || offset >= data.bytesize
69
+ return "" if length <= 0 || offset + length > data.bytesize
70
+
71
+ data.byteslice(offset, length)
72
+ end
73
+
74
+ # Public: Get the end offset of this match (exclusive).
75
+ #
76
+ # This convenience method calculates the byte position immediately after
77
+ # the last byte of this match, which is useful for range operations and
78
+ # avoiding overlapping matches.
79
+ #
80
+ # Examples
81
+ #
82
+ # match = PatternMatch.new(10, 5)
83
+ # match.end_offset # => 15
84
+ #
85
+ # Returns an Integer representing the end offset (exclusive).
86
+ def end_offset
87
+ offset + length
88
+ end
89
+
90
+ # Public: Check if this match overlaps with another match.
91
+ #
92
+ # This method determines whether two pattern matches have any overlapping
93
+ # bytes. This is useful for analyzing complex rules with multiple patterns
94
+ # or detecting redundant matches.
95
+ #
96
+ # other - Another PatternMatch instance to compare against
97
+ #
98
+ # Examples
99
+ #
100
+ # match1 = PatternMatch.new(10, 5) # bytes 10-14
101
+ # match2 = PatternMatch.new(12, 5) # bytes 12-16
102
+ # match1.overlaps?(match2) # => true
103
+ #
104
+ # match3 = PatternMatch.new(20, 5) # bytes 20-24
105
+ # match1.overlaps?(match3) # => false
106
+ #
107
+ # Returns a Boolean indicating whether the matches overlap.
108
+ def overlaps?(other)
109
+ offset < other.end_offset && end_offset > other.offset
110
+ end
111
+
112
+ # Public: Get a human-readable string representation of this match.
113
+ #
114
+ # This method provides a concise string representation showing the key
115
+ # details of the match, useful for debugging and logging purposes.
116
+ #
117
+ # Examples
118
+ #
119
+ # match = PatternMatch.new(42, 10)
120
+ # match.to_s # => "PatternMatch(offset: 42, length: 10)"
121
+ #
122
+ # Returns a String representation of this match.
123
+ def to_s
124
+ "PatternMatch(offset: #{offset}, length: #{length})"
125
+ end
126
+
127
+ # Public: Detailed inspection string with all attributes.
128
+ #
129
+ # Provides a complete string representation including all match attributes,
130
+ # useful for debugging and development purposes.
131
+ #
132
+ # Examples
133
+ #
134
+ # match = PatternMatch.new(42, 10)
135
+ # match.inspect # => "#<Yara::PatternMatch:0x... @offset=42, @length=10>"
136
+ #
137
+ # Returns a String with detailed object information.
138
+ def inspect
139
+ "#<#{self.class}:0x#{object_id.to_s(16)} @offset=#{@offset}, @length=#{@length}>"
140
+ end
141
+
142
+ # Public: Compare two PatternMatch objects for equality.
143
+ #
144
+ # Two matches are considered equal if they have the same offset and length.
145
+ # This is useful for deduplicating matches or comparing results.
146
+ #
147
+ # other - Another PatternMatch instance to compare against
148
+ #
149
+ # Examples
150
+ #
151
+ # match1 = PatternMatch.new(10, 5)
152
+ # match2 = PatternMatch.new(10, 5)
153
+ # match1 == match2 # => true
154
+ #
155
+ # Returns a Boolean indicating equality.
156
+ def ==(other)
157
+ other.is_a?(PatternMatch) && offset == other.offset && length == other.length
158
+ end
159
+
160
+ # Public: Generate hash code for this match.
161
+ #
162
+ # Uses offset and length to generate a hash code, enabling PatternMatch
163
+ # instances to be used as hash keys or in sets.
164
+ #
165
+ # Examples
166
+ #
167
+ # match = PatternMatch.new(42, 10)
168
+ # {match => "info"} # Can be used as hash key
169
+ #
170
+ # Returns an Integer hash code.
171
+ def hash
172
+ [offset, length].hash
173
+ end
174
+
175
+ # Public: Enable hash equality based on hash code.
176
+ alias_method :eql?, :==
177
+ end
178
+ end