Python interface for YARA, a powerful malware identification and classification tool
Overall
score
85%
Evaluation — 85%
↓ 0.94xAgent success when using this tile
YARA-Python provides configuration options for the YARA engine and a comprehensive exception hierarchy for handling various error conditions during rule compilation and scanning operations.
Configure YARA engine parameters to optimize performance and resource usage for specific use cases.
def set_config(stack_size=None, max_strings_per_rule=None):
"""
Set YARA configuration variables.
Parameters:
- stack_size (int, optional): Maximum stack size for YARA engine
- max_strings_per_rule (int, optional): Maximum number of strings per rule
Notes:
Configuration changes affect all subsequent rule compilation and matching operations.
"""Stack size configuration:
import yara
# Set maximum stack size (in bytes)
yara.set_config(stack_size=65536) # 64KB stack
# This affects recursion depth in complex rules
rules = yara.compile(source='''
rule DeepRecursion {
condition:
// Complex nested conditions that may require more stack space
true
}
''')String limit configuration:
# Set maximum strings per rule
yara.set_config(max_strings_per_rule=10000)
# Allows compilation of rules with many strings
rules = yara.compile(source='''
rule ManyStrings {
strings:
$s1 = "pattern1"
$s2 = "pattern2"
// ... many more strings up to the limit
condition:
any of them
}
''')Combined configuration:
# Configure multiple parameters
yara.set_config(
stack_size=131072, # 128KB stack
max_strings_per_rule=5000 # Up to 5000 strings per rule
)YARA-Python provides a structured exception hierarchy for handling different error conditions.
class Error(Exception):
"""Base exception class for all YARA-related errors."""
class SyntaxError(Error):
"""Raised when YARA rules contain syntax errors."""
class TimeoutError(Error):
"""Raised when scanning operations exceed timeout limits."""
class WarningError(Error):
"""Raised for warning conditions when error_on_warning is enabled."""Handle rule compilation errors with detailed error information.
Basic syntax error handling:
import yara
try:
# Invalid rule syntax
rules = yara.compile(source='''
rule InvalidRule {
strings:
$missing_quote = "unclosed string
condition:
$missing_quote
}
''')
except yara.SyntaxError as e:
print(f"Rule compilation failed: {e}")
# Handle syntax error - perhaps show user-friendly messageAdvanced syntax error handling:
def compile_rules_safely(rule_source, rule_name="Unknown"):
"""Safely compile rules with detailed error reporting."""
try:
return yara.compile(source=rule_source)
except yara.SyntaxError as e:
print(f"Syntax error in rule '{rule_name}':")
print(f" Error: {e}")
print(f" Rule source preview:")
for i, line in enumerate(rule_source.split('\n')[:5], 1):
print(f" {i}: {line}")
return None
except yara.Error as e:
print(f"General YARA error in rule '{rule_name}': {e}")
return None
# Usage
rules = compile_rules_safely(invalid_rule_source, "MyRule")
if rules is None:
print("Rule compilation failed, using fallback rules")Handle scanning timeout conditions gracefully.
Timeout handling with fallback:
def scan_with_timeout(rules, target_file, max_timeout=60):
"""Scan file with timeout and fallback strategies."""
try:
return rules.match(filepath=target_file, timeout=max_timeout)
except yara.TimeoutError:
print(f"Scan of {target_file} timed out after {max_timeout}s")
# Try with fast mode as fallback
try:
print("Retrying with fast mode...")
return rules.match(filepath=target_file, timeout=30, fast=True)
except yara.TimeoutError:
print("Fast mode scan also timed out")
return [] # Return empty results
except yara.Error as e:
print(f"Scan error: {e}")
return []
# Usage
matches = scan_with_timeout(rules, "/path/to/large_file.bin")Handle warning conditions when strict error checking is enabled.
Warning as error handling:
def compile_strict_rules(rule_source):
"""Compile rules with warnings treated as errors."""
try:
return yara.compile(
source=rule_source,
error_on_warning=True
)
except yara.WarningError as e:
print(f"Rule warning (treated as error): {e}")
print("Consider revising rule to eliminate warnings")
return None
except yara.SyntaxError as e:
print(f"Rule syntax error: {e}")
return None
# Usage with potentially problematic rule
rule_with_warnings = '''
rule PotentialWarning {
strings:
$unused = "never_referenced" // May generate warning
condition:
true // Doesn't use $unused
}
'''
rules = compile_strict_rules(rule_with_warnings)A complete error handling strategy for production use.
Production-ready error handling:
import yara
import logging
class YaraManager:
"""Production YARA rule manager with comprehensive error handling."""
def __init__(self, stack_size=65536, max_strings=10000):
"""Initialize with custom configuration."""
try:
yara.set_config(
stack_size=stack_size,
max_strings_per_rule=max_strings
)
logging.info(f"YARA configured: stack={stack_size}, max_strings={max_strings}")
except Exception as e:
logging.error(f"YARA configuration failed: {e}")
raise
def compile_rules(self, rule_sources, externals=None):
"""Compile rules with comprehensive error handling."""
try:
if isinstance(rule_sources, str):
# Single rule source
return yara.compile(source=rule_sources, externals=externals)
elif isinstance(rule_sources, dict):
# Multiple sources with namespaces
return yara.compile(sources=rule_sources, externals=externals)
else:
raise ValueError("rule_sources must be string or dict")
except yara.SyntaxError as e:
logging.error(f"Rule syntax error: {e}")
raise
except yara.Error as e:
logging.error(f"YARA compilation error: {e}")
raise
except Exception as e:
logging.error(f"Unexpected error during compilation: {e}")
raise
def scan_target(self, rules, target, scan_timeout=120):
"""Scan target with comprehensive error handling."""
try:
if isinstance(target, str):
if target.startswith('/') or '\\' in target:
# File path
return rules.match(filepath=target, timeout=scan_timeout)
else:
# String data
return rules.match(data=target, timeout=scan_timeout)
elif isinstance(target, bytes):
# Binary data
return rules.match(data=target, timeout=scan_timeout)
elif isinstance(target, int):
# Process ID
return rules.match(pid=target, timeout=scan_timeout)
else:
raise ValueError("Unsupported target type")
except yara.TimeoutError:
logging.warning(f"Scan timed out after {scan_timeout}s")
return [] # Return empty results instead of raising
except yara.Error as e:
logging.error(f"YARA scan error: {e}")
raise
except PermissionError as e:
logging.error(f"Permission denied during scan: {e}")
return []
except Exception as e:
logging.error(f"Unexpected error during scan: {e}")
raise
# Usage example
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
manager = YaraManager()
try:
# Compile rules
rules = manager.compile_rules('''
rule TestRule {
strings:
$test = "malicious"
condition:
$test
}
''')
# Scan various targets
results1 = manager.scan_target(rules, "test malicious data")
results2 = manager.scan_target(rules, "/path/to/file.bin")
results3 = manager.scan_target(rules, 1234) # Process ID
print(f"Scan results: {len(results1 + results2 + results3)} total matches")
except Exception as e:
logging.error(f"YARA operation failed: {e}")Implement robust error recovery for mission-critical applications.
Graceful degradation:
def resilient_scan(rule_files, target_files):
"""Perform scanning with graceful degradation on errors."""
successful_scans = 0
total_matches = []
for rule_file in rule_files:
try:
# Try to compile each rule file
rules = yara.compile(filepath=rule_file)
for target_file in target_files:
try:
# Try to scan each target
matches = rules.match(filepath=target_file, timeout=30)
total_matches.extend(matches)
successful_scans += 1
except yara.TimeoutError:
# Try fast mode on timeout
try:
fast_matches = rules.match(filepath=target_file, fast=True, timeout=10)
total_matches.extend(fast_matches)
successful_scans += 1
except:
logging.warning(f"Failed to scan {target_file} with {rule_file}")
except Exception as e:
logging.warning(f"Scan error {target_file}: {e}")
continue
except yara.SyntaxError as e:
logging.error(f"Invalid rule file {rule_file}: {e}")
continue
except Exception as e:
logging.error(f"Failed to load {rule_file}: {e}")
continue
logging.info(f"Completed {successful_scans} successful scans")
return total_matchesInstall with Tessl CLI
npx tessl i tessl/pypi-yara-pythonevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10