GranularFireplace commited on
Commit
3a2ea2f
·
verified ·
1 Parent(s): 9885f25
Files changed (1) hide show
  1. app.py +65 -12
app.py CHANGED
@@ -65,31 +65,84 @@ async def clone_yara_repo():
65
  logger.error(f"Error cloning YARA repository: {str(e)}")
66
  return None
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  def compile_yara_rules(repo_path: Path) -> Optional[yara.Rules]:
69
- """Compile YARA rules from repository"""
70
  try:
71
- yara_files = list(repo_path.glob("**/*.yar"))
 
 
72
  if not yara_files:
73
- logger.warning("No YARA files found in repository")
74
  return None
75
 
76
- logger.info(f"Found {len(yara_files)} YARA files, compiling rules")
77
  rules = {}
78
 
79
  for yara_file in yara_files:
80
  try:
81
- rules[str(yara_file)] = str(yara_file)
 
 
82
  except Exception as e:
83
- logger.warning(f"Error processing {yara_file}: {str(e)}")
84
 
85
- return yara.compile(filepaths=rules)
86
-
87
- except yara.SyntaxError as e:
88
- logger.error(f"YARA syntax error: {str(e)}")
 
 
 
89
  except Exception as e:
90
  logger.error(f"Error compiling YARA rules: {str(e)}")
91
-
92
- return None
93
 
94
  @asynccontextmanager
95
  async def lifespan(app: FastAPI):
 
65
  logger.error(f"Error cloning YARA repository: {str(e)}")
66
  return None
67
 
68
+ def preprocess_yara_rules(repo_path: Path) -> Path:
69
+ """Preprocess YARA rules to fix syntax issues"""
70
+ processed_dir = Path("processed_yara_rules")
71
+ if processed_dir.exists():
72
+ shutil.rmtree(processed_dir)
73
+ processed_dir.mkdir()
74
+
75
+ for yara_file in repo_path.glob("**/*.yar"):
76
+ try:
77
+ content = yara_file.read_text(encoding='utf-8', errors='replace')
78
+
79
+ # Fix invalid rule names and string identifiers
80
+ processed_content = []
81
+ rule_counter = 1
82
+ string_counter = 1
83
+ current_rule = None
84
+
85
+ for line in content.split('\n'):
86
+ # Normalize rule names
87
+ if line.strip().startswith('rule '):
88
+ rule_name = line.split('{')[0].split('rule ')[1].strip()
89
+ # Replace invalid characters and ensure unique names
90
+ clean_name = rule_name.replace('#', '').replace(' ', '_').replace('-', '_')
91
+ clean_name = f"Rule_{rule_counter}_{clean_name}"[:128]
92
+ processed_content.append(f"rule {clean_name} {{")
93
+ current_rule = clean_name
94
+ rule_counter += 1
95
+ string_counter = 1
96
+ # Make string identifiers unique per rule
97
+ elif '$a_01_' in line and current_rule:
98
+ new_id = f"${current_rule}_str_{string_counter}"
99
+ line = line.replace('$a_01_', new_id, 1)
100
+ string_counter += 1
101
+ processed_content.append(line)
102
+ else:
103
+ processed_content.append(line)
104
+
105
+ # Save processed file
106
+ processed_file = processed_dir / yara_file.name
107
+ processed_file.write_text('\n'.join(processed_content))
108
+
109
+ except Exception as e:
110
+ logger.warning(f"Error processing {yara_file}: {str(e)}")
111
+ continue
112
+
113
+ return processed_dir
114
+
115
  def compile_yara_rules(repo_path: Path) -> Optional[yara.Rules]:
116
+ """Compile YARA rules from repository with error handling"""
117
  try:
118
+ processed_dir = preprocess_yara_rules(repo_path)
119
+ yara_files = list(processed_dir.glob("**/*.yar"))
120
+
121
  if not yara_files:
122
+ logger.warning("No valid YARA files after preprocessing")
123
  return None
124
 
125
+ logger.info(f"Compiling {len(yara_files)} processed YARA files")
126
  rules = {}
127
 
128
  for yara_file in yara_files:
129
  try:
130
+ # Use namespace based on file path to avoid conflicts
131
+ namespace = str(yara_file.relative_to(processed_dir)).replace('/', '_')
132
+ rules[namespace] = str(yara_file)
133
  except Exception as e:
134
+ logger.warning(f"Error adding {yara_file}: {str(e)}")
135
 
136
+ # Compile with error handling
137
+ try:
138
+ return yara.compile(filepaths=rules, error_on_warning=False)
139
+ except yara.SyntaxError as e:
140
+ logger.error(f"YARA syntax error in processed rules: {str(e)}")
141
+ return None
142
+
143
  except Exception as e:
144
  logger.error(f"Error compiling YARA rules: {str(e)}")
145
+ return None
 
146
 
147
  @asynccontextmanager
148
  async def lifespan(app: FastAPI):