iflow-mcp_developermode-korea_reversecore-mcp 1.0.0__py3-none-any.whl

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.
Files changed (79) hide show
  1. iflow_mcp_developermode_korea_reversecore_mcp-1.0.0.dist-info/METADATA +543 -0
  2. iflow_mcp_developermode_korea_reversecore_mcp-1.0.0.dist-info/RECORD +79 -0
  3. iflow_mcp_developermode_korea_reversecore_mcp-1.0.0.dist-info/WHEEL +5 -0
  4. iflow_mcp_developermode_korea_reversecore_mcp-1.0.0.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_developermode_korea_reversecore_mcp-1.0.0.dist-info/licenses/LICENSE +21 -0
  6. iflow_mcp_developermode_korea_reversecore_mcp-1.0.0.dist-info/top_level.txt +1 -0
  7. reversecore_mcp/__init__.py +9 -0
  8. reversecore_mcp/core/__init__.py +78 -0
  9. reversecore_mcp/core/audit.py +101 -0
  10. reversecore_mcp/core/binary_cache.py +138 -0
  11. reversecore_mcp/core/command_spec.py +357 -0
  12. reversecore_mcp/core/config.py +432 -0
  13. reversecore_mcp/core/container.py +288 -0
  14. reversecore_mcp/core/decorators.py +152 -0
  15. reversecore_mcp/core/error_formatting.py +93 -0
  16. reversecore_mcp/core/error_handling.py +142 -0
  17. reversecore_mcp/core/evidence.py +229 -0
  18. reversecore_mcp/core/exceptions.py +296 -0
  19. reversecore_mcp/core/execution.py +240 -0
  20. reversecore_mcp/core/ghidra.py +642 -0
  21. reversecore_mcp/core/ghidra_helper.py +481 -0
  22. reversecore_mcp/core/ghidra_manager.py +234 -0
  23. reversecore_mcp/core/json_utils.py +131 -0
  24. reversecore_mcp/core/loader.py +73 -0
  25. reversecore_mcp/core/logging_config.py +206 -0
  26. reversecore_mcp/core/memory.py +721 -0
  27. reversecore_mcp/core/metrics.py +198 -0
  28. reversecore_mcp/core/mitre_mapper.py +365 -0
  29. reversecore_mcp/core/plugin.py +45 -0
  30. reversecore_mcp/core/r2_helpers.py +404 -0
  31. reversecore_mcp/core/r2_pool.py +403 -0
  32. reversecore_mcp/core/report_generator.py +268 -0
  33. reversecore_mcp/core/resilience.py +252 -0
  34. reversecore_mcp/core/resource_manager.py +169 -0
  35. reversecore_mcp/core/result.py +132 -0
  36. reversecore_mcp/core/security.py +213 -0
  37. reversecore_mcp/core/validators.py +238 -0
  38. reversecore_mcp/dashboard/__init__.py +221 -0
  39. reversecore_mcp/prompts/__init__.py +56 -0
  40. reversecore_mcp/prompts/common.py +24 -0
  41. reversecore_mcp/prompts/game.py +280 -0
  42. reversecore_mcp/prompts/malware.py +1219 -0
  43. reversecore_mcp/prompts/report.py +150 -0
  44. reversecore_mcp/prompts/security.py +136 -0
  45. reversecore_mcp/resources.py +329 -0
  46. reversecore_mcp/server.py +727 -0
  47. reversecore_mcp/tools/__init__.py +49 -0
  48. reversecore_mcp/tools/analysis/__init__.py +74 -0
  49. reversecore_mcp/tools/analysis/capa_tools.py +215 -0
  50. reversecore_mcp/tools/analysis/die_tools.py +180 -0
  51. reversecore_mcp/tools/analysis/diff_tools.py +643 -0
  52. reversecore_mcp/tools/analysis/lief_tools.py +272 -0
  53. reversecore_mcp/tools/analysis/signature_tools.py +591 -0
  54. reversecore_mcp/tools/analysis/static_analysis.py +479 -0
  55. reversecore_mcp/tools/common/__init__.py +58 -0
  56. reversecore_mcp/tools/common/file_operations.py +352 -0
  57. reversecore_mcp/tools/common/memory_tools.py +516 -0
  58. reversecore_mcp/tools/common/patch_explainer.py +230 -0
  59. reversecore_mcp/tools/common/server_tools.py +115 -0
  60. reversecore_mcp/tools/ghidra/__init__.py +19 -0
  61. reversecore_mcp/tools/ghidra/decompilation.py +975 -0
  62. reversecore_mcp/tools/ghidra/ghidra_tools.py +1052 -0
  63. reversecore_mcp/tools/malware/__init__.py +61 -0
  64. reversecore_mcp/tools/malware/adaptive_vaccine.py +579 -0
  65. reversecore_mcp/tools/malware/dormant_detector.py +756 -0
  66. reversecore_mcp/tools/malware/ioc_tools.py +228 -0
  67. reversecore_mcp/tools/malware/vulnerability_hunter.py +519 -0
  68. reversecore_mcp/tools/malware/yara_tools.py +214 -0
  69. reversecore_mcp/tools/patch_explainer.py +19 -0
  70. reversecore_mcp/tools/radare2/__init__.py +13 -0
  71. reversecore_mcp/tools/radare2/r2_analysis.py +972 -0
  72. reversecore_mcp/tools/radare2/r2_session.py +376 -0
  73. reversecore_mcp/tools/radare2/radare2_mcp_tools.py +1183 -0
  74. reversecore_mcp/tools/report/__init__.py +4 -0
  75. reversecore_mcp/tools/report/email.py +82 -0
  76. reversecore_mcp/tools/report/report_mcp_tools.py +344 -0
  77. reversecore_mcp/tools/report/report_tools.py +1076 -0
  78. reversecore_mcp/tools/report/session.py +194 -0
  79. reversecore_mcp/tools/report_tools.py +11 -0
@@ -0,0 +1,519 @@
1
+ """
2
+ Vulnerability Hunter: Automated Vulnerability Discovery Tool.
3
+
4
+ This tool combines multiple analysis techniques to automatically discover
5
+ potential security vulnerabilities in binary files:
6
+
7
+ 1. Dangerous API Detection - Finds calls to unsafe functions
8
+ 2. Backtrace Analysis - Traces execution paths to dangerous calls
9
+ 3. Light Taint Analysis - Identifies user-controllable inputs
10
+ 4. Report Generation - Creates vulnerability reports with YARA rules
11
+
12
+ This is a signature tool that combines: decompilation, xrefs, signature_tools, dormant_detector
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import re
18
+ from functools import lru_cache
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from async_lru import alru_cache
23
+ from fastmcp import Context, FastMCP
24
+
25
+ from reversecore_mcp.core import json_utils as json
26
+ from reversecore_mcp.core.config import get_config
27
+ from reversecore_mcp.core.decorators import log_execution
28
+ from reversecore_mcp.core.error_handling import handle_tool_errors
29
+ from reversecore_mcp.core.execution import execute_subprocess_async
30
+ from reversecore_mcp.core.logging_config import get_logger
31
+ from reversecore_mcp.core.metrics import track_metrics
32
+ from reversecore_mcp.core.r2_helpers import calculate_dynamic_timeout
33
+ from reversecore_mcp.core.result import ToolResult, failure, success
34
+ from reversecore_mcp.core.security import validate_file_path
35
+
36
+ logger = get_logger(__name__)
37
+
38
+ DEFAULT_TIMEOUT = get_config().default_tool_timeout
39
+
40
+ # =============================================================================
41
+ # Dangerous API Database
42
+ # =============================================================================
43
+
44
+ # Categorized dangerous APIs with severity and description
45
+ DANGEROUS_APIS: dict[str, dict[str, Any]] = {
46
+ # Memory Corruption - Critical
47
+ "strcpy": {"severity": "critical", "category": "buffer_overflow", "description": "Unbounded string copy"},
48
+ "strcat": {"severity": "critical", "category": "buffer_overflow", "description": "Unbounded string concatenation"},
49
+ "sprintf": {"severity": "critical", "category": "buffer_overflow", "description": "Unbounded formatted string"},
50
+ "gets": {"severity": "critical", "category": "buffer_overflow", "description": "Unbounded input read"},
51
+ "scanf": {"severity": "high", "category": "buffer_overflow", "description": "Potentially unbounded input"},
52
+ "vsprintf": {"severity": "critical", "category": "buffer_overflow", "description": "Unbounded formatted string (va)"},
53
+
54
+ # Format String
55
+ "printf": {"severity": "medium", "category": "format_string", "description": "Format string if user-controlled"},
56
+ "fprintf": {"severity": "medium", "category": "format_string", "description": "Format string if user-controlled"},
57
+ "syslog": {"severity": "medium", "category": "format_string", "description": "Format string in logging"},
58
+
59
+ # Command Injection - Critical
60
+ "system": {"severity": "critical", "category": "command_injection", "description": "Shell command execution"},
61
+ "popen": {"severity": "critical", "category": "command_injection", "description": "Shell command with pipe"},
62
+ "execve": {"severity": "critical", "category": "command_injection", "description": "Process execution"},
63
+ "execl": {"severity": "critical", "category": "command_injection", "description": "Process execution"},
64
+ "execlp": {"severity": "critical", "category": "command_injection", "description": "Process execution (PATH)"},
65
+ "execvp": {"severity": "critical", "category": "command_injection", "description": "Process execution (PATH)"},
66
+ "ShellExecute": {"severity": "critical", "category": "command_injection", "description": "Windows shell execution"},
67
+ "ShellExecuteA": {"severity": "critical", "category": "command_injection", "description": "Windows shell execution"},
68
+ "ShellExecuteW": {"severity": "critical", "category": "command_injection", "description": "Windows shell execution"},
69
+ "WinExec": {"severity": "critical", "category": "command_injection", "description": "Windows process execution"},
70
+ "CreateProcess": {"severity": "high", "category": "command_injection", "description": "Windows process creation"},
71
+ "CreateProcessA": {"severity": "high", "category": "command_injection", "description": "Windows process creation"},
72
+ "CreateProcessW": {"severity": "high", "category": "command_injection", "description": "Windows process creation"},
73
+
74
+ # Memory Management
75
+ "malloc": {"severity": "low", "category": "memory", "description": "Dynamic allocation (check for integer overflow)"},
76
+ "realloc": {"severity": "medium", "category": "memory", "description": "Reallocation (check for size)"},
77
+ "free": {"severity": "medium", "category": "memory", "description": "Free (check for double-free/UAF)"},
78
+ "VirtualAlloc": {"severity": "low", "category": "memory", "description": "Windows memory allocation"},
79
+ "HeapAlloc": {"severity": "low", "category": "memory", "description": "Windows heap allocation"},
80
+
81
+ # File Operations
82
+ "fopen": {"severity": "low", "category": "file_access", "description": "File open (check path)"},
83
+ "open": {"severity": "low", "category": "file_access", "description": "File open (check path)"},
84
+ "CreateFile": {"severity": "low", "category": "file_access", "description": "Windows file open"},
85
+ "CreateFileA": {"severity": "low", "category": "file_access", "description": "Windows file open"},
86
+ "CreateFileW": {"severity": "low", "category": "file_access", "description": "Windows file open"},
87
+ "unlink": {"severity": "medium", "category": "file_access", "description": "File deletion"},
88
+ "remove": {"severity": "medium", "category": "file_access", "description": "File deletion"},
89
+ "DeleteFile": {"severity": "medium", "category": "file_access", "description": "Windows file deletion"},
90
+
91
+ # Network
92
+ "recv": {"severity": "high", "category": "network_input", "description": "Network receive (user input source)"},
93
+ "recvfrom": {"severity": "high", "category": "network_input", "description": "Network receive (user input source)"},
94
+ "read": {"severity": "medium", "category": "input", "description": "Read (potential user input)"},
95
+ "fread": {"severity": "medium", "category": "input", "description": "File read (potential user input)"},
96
+ "fgets": {"severity": "low", "category": "input", "description": "Bounded string read"},
97
+ "getenv": {"severity": "medium", "category": "input", "description": "Environment variable (user-controlled)"},
98
+
99
+ # Dangerous Windows APIs
100
+ "LoadLibrary": {"severity": "high", "category": "code_execution", "description": "DLL loading"},
101
+ "LoadLibraryA": {"severity": "high", "category": "code_execution", "description": "DLL loading"},
102
+ "LoadLibraryW": {"severity": "high", "category": "code_execution", "description": "DLL loading"},
103
+ "GetProcAddress": {"severity": "medium", "category": "code_execution", "description": "Dynamic function resolution"},
104
+ "WriteProcessMemory": {"severity": "critical", "category": "code_injection", "description": "Process memory write"},
105
+ "VirtualAllocEx": {"severity": "high", "category": "code_injection", "description": "Remote memory allocation"},
106
+ "CreateRemoteThread": {"severity": "critical", "category": "code_injection", "description": "Remote thread creation"},
107
+
108
+ # Crypto (weak)
109
+ "rand": {"severity": "medium", "category": "weak_crypto", "description": "Weak random number generator"},
110
+ "srand": {"severity": "low", "category": "weak_crypto", "description": "Weak RNG seed"},
111
+ "MD5": {"severity": "medium", "category": "weak_crypto", "description": "Weak hash algorithm"},
112
+ "SHA1": {"severity": "low", "category": "weak_crypto", "description": "Deprecated hash algorithm"},
113
+ }
114
+
115
+ # User input sources for taint analysis
116
+ USER_INPUT_SOURCES = frozenset({
117
+ "recv", "recvfrom", "read", "fread", "fgets", "gets", "scanf",
118
+ "getenv", "argv", "fopen", "open", "accept", "listen",
119
+ "ReadFile", "InternetReadFile", "HttpQueryInfo",
120
+ })
121
+
122
+ # Pre-compiled pattern for hex addresses
123
+ _HEX_PATTERN = re.compile(r"0x[0-9a-fA-F]+")
124
+
125
+
126
+ def _extract_json_safely(output: str) -> Any | None:
127
+ """Extract JSON from radare2 output using robust state-machine parser.
128
+
129
+ Delegates to r2_helpers.parse_json_output which uses O(n) algorithm
130
+ instead of fragile regex patterns.
131
+ """
132
+ if not output or not output.strip():
133
+ return None
134
+
135
+ try:
136
+ from reversecore_mcp.core.r2_helpers import parse_json_output
137
+ return parse_json_output(output)
138
+ except Exception:
139
+ return None
140
+
141
+
142
+ async def _run_r2_cmd(file_path: str | Path, cmd: str, timeout: int | None = None) -> str:
143
+ """Execute radare2 command."""
144
+ effective_timeout = timeout or calculate_dynamic_timeout(str(file_path), base_timeout=30)
145
+ full_cmd = ["radare2", "-q", "-c", cmd, str(file_path)]
146
+ output, _ = await execute_subprocess_async(full_cmd, timeout=effective_timeout)
147
+ return output
148
+
149
+
150
+ @log_execution(tool_name="vulnerability_hunter")
151
+ @track_metrics("vulnerability_hunter")
152
+ @handle_tool_errors
153
+ async def vulnerability_hunter(
154
+ file_path: str,
155
+ max_depth: int = 3,
156
+ severity_filter: str = "all",
157
+ generate_yara: bool = True,
158
+ timeout: int = 300,
159
+ ctx: Context = None,
160
+ ) -> ToolResult:
161
+ """
162
+ Automated vulnerability discovery combining multiple analysis techniques.
163
+
164
+ This tool performs a comprehensive security analysis:
165
+ 1. Scans for dangerous API calls (buffer overflow, command injection, etc.)
166
+ 2. Traces back to find how each dangerous call is reached
167
+ 3. Identifies if inputs are user-controllable (light taint analysis)
168
+ 4. Generates vulnerability report with YARA detection rules
169
+
170
+ Args:
171
+ file_path: Path to the binary file to analyze
172
+ max_depth: Maximum backtrace depth for call chain analysis (default: 3)
173
+ severity_filter: Filter by severity - "all", "critical", "high", "medium" (default: "all")
174
+ generate_yara: Generate YARA rules for detected vulnerabilities (default: True)
175
+ timeout: Analysis timeout in seconds (default: 300)
176
+
177
+ Returns:
178
+ ToolResult containing:
179
+ - vulnerabilities: List of detected vulnerabilities with details
180
+ - call_chains: Execution paths leading to vulnerabilities
181
+ - taint_sources: Identified user input sources
182
+ - yara_rules: Generated YARA detection rules (if enabled)
183
+ - summary: Statistics and risk assessment
184
+
185
+ Example:
186
+ vulnerability_hunter("/path/to/binary.exe", severity_filter="critical")
187
+ """
188
+ validated_path = validate_file_path(file_path)
189
+
190
+ if ctx:
191
+ await ctx.info("🔍 Vulnerability Hunter: Starting comprehensive analysis...")
192
+
193
+ # Phase 1: Analyze and get function list
194
+ if ctx:
195
+ await ctx.report_progress(10, 100)
196
+ await ctx.info("📊 Phase 1: Analyzing binary and enumerating functions...")
197
+
198
+ file_size = validated_path.stat().st_size
199
+ analysis_cmd = "aa" if file_size > 5_000_000 else "aaa"
200
+
201
+ output = await _run_r2_cmd(validated_path, f"{analysis_cmd}; aflj", timeout=timeout)
202
+ functions = _extract_json_safely(output)
203
+
204
+ if not functions or not isinstance(functions, list):
205
+ return failure(
206
+ "ANALYSIS_ERROR",
207
+ "Failed to analyze binary or extract function list",
208
+ hint="Try increasing timeout or check if the binary is valid"
209
+ )
210
+
211
+ # Phase 2: Find dangerous API calls
212
+ if ctx:
213
+ await ctx.report_progress(25, 100)
214
+ await ctx.info("⚠️ Phase 2: Scanning for dangerous API calls...")
215
+
216
+ vulnerabilities = []
217
+ dangerous_calls = []
218
+
219
+ # Build function name index for faster lookup
220
+ func_by_name = {f.get("name", ""): f for f in functions}
221
+ func_by_addr = {f.get("offset", 0): f for f in functions}
222
+
223
+ # Find imports that match dangerous APIs
224
+ imports_output = await _run_r2_cmd(validated_path, "iij", timeout=60)
225
+ imports = _extract_json_safely(imports_output) or []
226
+
227
+ for imp in imports:
228
+ imp_name = imp.get("name", "")
229
+ # Extract base function name (remove sym.imp. prefix and library suffix)
230
+ base_name = imp_name.replace("sym.imp.", "").split("@")[0]
231
+
232
+ if base_name in DANGEROUS_APIS:
233
+ api_info = DANGEROUS_APIS[base_name]
234
+
235
+ # Apply severity filter
236
+ if severity_filter != "all":
237
+ severity_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
238
+ filter_level = severity_order.get(severity_filter, 3)
239
+ api_level = severity_order.get(api_info["severity"], 3)
240
+ if api_level > filter_level:
241
+ continue
242
+
243
+ dangerous_calls.append({
244
+ "dangerous_api_name": base_name,
245
+ "import_symbol_full_name": imp_name,
246
+ "plt_address": hex(imp.get("plt", 0) or imp.get("vaddr", 0)),
247
+ "vulnerability_category": api_info["category"],
248
+ "severity_level": api_info["severity"],
249
+ "risk_description": api_info["description"],
250
+ })
251
+
252
+ if ctx:
253
+ await ctx.info(f" Found {len(dangerous_calls)} dangerous API calls")
254
+
255
+ # Phase 3: Backtrace analysis for each dangerous call
256
+ if ctx:
257
+ await ctx.report_progress(40, 100)
258
+ await ctx.info("🔙 Phase 3: Analyzing call chains (backtrace)...")
259
+
260
+ call_chains = []
261
+ taint_sources = []
262
+
263
+ for i, dangerous in enumerate(dangerous_calls[:20]): # Limit for performance
264
+ if ctx and i % 5 == 0:
265
+ await ctx.report_progress(40 + int((i / min(len(dangerous_calls), 20)) * 30), 100)
266
+
267
+ api_plt_address = dangerous["plt_address"]
268
+
269
+ # Get cross-references TO this function
270
+ xrefs_output = await _run_r2_cmd(validated_path, f"axtj @ {api_plt_address}", timeout=30)
271
+ xrefs = _extract_json_safely(xrefs_output) or []
272
+
273
+ chain_results = []
274
+ for xref in xrefs[:10]: # Limit xrefs per function
275
+ caller_addr = xref.get("from", 0)
276
+ caller_func = None
277
+
278
+ # Find which function contains this caller
279
+ for func in functions:
280
+ func_start = func.get("offset", 0)
281
+ func_size = func.get("size", 0)
282
+ if func_start <= caller_addr < func_start + func_size:
283
+ caller_func = func
284
+ break
285
+
286
+ if caller_func:
287
+ func_name = caller_func.get("name", "unknown")
288
+
289
+ # Check if this function receives user input (light taint analysis)
290
+ is_tainted = False
291
+ taint_source = None
292
+
293
+ # Get function disassembly to check for input sources
294
+ func_addr = caller_func.get("offset", 0)
295
+ disasm_output = await _run_r2_cmd(
296
+ validated_path, f"pdfj @ {hex(func_addr)}", timeout=30
297
+ )
298
+ func_disasm = _extract_json_safely(disasm_output)
299
+
300
+ if func_disasm and "ops" in func_disasm:
301
+ for op in func_disasm.get("ops", []):
302
+ disasm = op.get("disasm", "")
303
+ for source in USER_INPUT_SOURCES:
304
+ # Use word boundary to avoid false positives
305
+ # e.g., "pthread" should not match "read"
306
+ if re.search(rf"\b{re.escape(source)}\b", disasm):
307
+ is_tainted = True
308
+ taint_source = source
309
+ if source not in [t["input_source_api"] for t in taint_sources]:
310
+ taint_sources.append({
311
+ "input_source_api": source,
312
+ "found_in_function": func_name,
313
+ "instruction_address": hex(op.get("offset", 0))
314
+ })
315
+ break
316
+
317
+ chain_results.append({
318
+ "calling_function_name": func_name,
319
+ "call_instruction_address": hex(caller_addr),
320
+ "user_input_reaches_here": is_tainted,
321
+ "input_source_if_tainted": taint_source,
322
+ "reference_type": xref.get("type", "unknown")
323
+ })
324
+
325
+ call_chains.append({
326
+ "dangerous_api_name": dangerous["dangerous_api_name"],
327
+ "api_plt_address": dangerous["plt_address"],
328
+ "severity_level": dangerous["severity_level"],
329
+ "vulnerability_category": dangerous["vulnerability_category"],
330
+ "functions_that_call_this_api": chain_results,
331
+ "total_call_sites_found": len(xrefs)
332
+ })
333
+
334
+ # Create vulnerability entry for tainted paths
335
+ tainted_callers = [c for c in chain_results if c["user_input_reaches_here"]]
336
+ if tainted_callers:
337
+ vulnerabilities.append({
338
+ "vulnerability_type": dangerous["vulnerability_category"],
339
+ "severity_level": dangerous["severity_level"],
340
+ "dangerous_api_name": dangerous["dangerous_api_name"],
341
+ "api_plt_address": dangerous["plt_address"],
342
+ "risk_description": dangerous["risk_description"],
343
+ "is_exploitable": True,
344
+ "exploitation_reason": f"User input from {tainted_callers[0]['input_source_if_tainted']} reaches {dangerous['dangerous_api_name']}",
345
+ "vulnerable_functions": [c["calling_function_name"] for c in tainted_callers],
346
+ "fix_recommendation": _get_recommendation(dangerous["vulnerability_category"])
347
+ })
348
+ elif chain_results:
349
+ vulnerabilities.append({
350
+ "vulnerability_type": dangerous["vulnerability_category"],
351
+ "severity_level": dangerous["severity_level"],
352
+ "dangerous_api_name": dangerous["dangerous_api_name"],
353
+ "api_plt_address": dangerous["plt_address"],
354
+ "risk_description": dangerous["risk_description"],
355
+ "is_exploitable": "needs_verification",
356
+ "exploitation_reason": f"Dangerous API {dangerous['dangerous_api_name']} called from {len(chain_results)} locations (taint not confirmed)",
357
+ "vulnerable_functions": [c["calling_function_name"] for c in chain_results[:5]],
358
+ "fix_recommendation": _get_recommendation(dangerous["vulnerability_category"])
359
+ })
360
+
361
+ # Phase 4: Generate YARA rules
362
+ yara_rules = []
363
+ if generate_yara and vulnerabilities:
364
+ if ctx:
365
+ await ctx.report_progress(85, 100)
366
+ await ctx.info("📝 Phase 4: Generating YARA detection rules...")
367
+
368
+ yara_rules = _generate_vulnerability_yara_rules(
369
+ vulnerabilities,
370
+ validated_path.name,
371
+ dangerous_calls
372
+ )
373
+
374
+ # Phase 5: Generate summary
375
+ if ctx:
376
+ await ctx.report_progress(95, 100)
377
+ await ctx.info("📋 Generating vulnerability report...")
378
+
379
+ severity_counts = {"critical": 0, "high": 0, "medium": 0, "low": 0}
380
+ for vuln in vulnerabilities:
381
+ sev = vuln.get("severity_level", "low")
382
+ severity_counts[sev] = severity_counts.get(sev, 0) + 1
383
+
384
+ exploitable_count = sum(1 for v in vulnerabilities if v.get("is_exploitable") is True)
385
+
386
+ risk_score = (
387
+ severity_counts["critical"] * 10 +
388
+ severity_counts["high"] * 5 +
389
+ severity_counts["medium"] * 2 +
390
+ severity_counts["low"] * 1
391
+ )
392
+
393
+ if risk_score >= 20:
394
+ risk_level = "CRITICAL"
395
+ elif risk_score >= 10:
396
+ risk_level = "HIGH"
397
+ elif risk_score >= 5:
398
+ risk_level = "MEDIUM"
399
+ else:
400
+ risk_level = "LOW"
401
+
402
+ if ctx:
403
+ await ctx.report_progress(100, 100)
404
+ await ctx.info(f"✅ Analysis complete. Risk Level: {risk_level}")
405
+
406
+ return success({
407
+ "analysis_summary": {
408
+ "total_vulnerabilities_found": len(vulnerabilities),
409
+ "confirmed_exploitable_count": exploitable_count,
410
+ "overall_risk_level": risk_level,
411
+ "risk_score_0_to_100": risk_score,
412
+ "vulnerabilities_by_severity": severity_counts,
413
+ "dangerous_imports_detected": len(dangerous_calls),
414
+ "user_input_sources_found": len(taint_sources),
415
+ },
416
+ "detected_vulnerabilities": vulnerabilities,
417
+ "call_chain_analysis": call_chains,
418
+ "user_input_sources": taint_sources,
419
+ "generated_yara_rules": yara_rules if generate_yara else None,
420
+ "prioritized_recommendations": _generate_recommendations(vulnerabilities),
421
+ })
422
+
423
+
424
+ def _get_recommendation(category: str) -> str:
425
+ """Get security recommendation for vulnerability category."""
426
+ recommendations = {
427
+ "buffer_overflow": "Use bounded alternatives (strncpy, snprintf) and validate buffer sizes",
428
+ "format_string": "Never use user input as format string. Use printf(\"%s\", user_input)",
429
+ "command_injection": "Avoid shell commands. Use exec* with explicit arguments, sanitize inputs",
430
+ "memory": "Check allocation sizes for integer overflow, use RAII/smart pointers",
431
+ "file_access": "Validate and sanitize file paths, use allowlists",
432
+ "network_input": "Validate all network input, use bounded reads with size limits",
433
+ "input": "Validate and sanitize all user input before use",
434
+ "code_execution": "Validate DLL/library paths, use signed code where possible",
435
+ "code_injection": "This is typical malware behavior - investigate thoroughly",
436
+ "weak_crypto": "Use cryptographically secure random (getrandom, CryptGenRandom)",
437
+ }
438
+ return recommendations.get(category, "Review and validate all inputs to this function")
439
+
440
+
441
+ def _generate_recommendations(vulnerabilities: list[dict]) -> list[str]:
442
+ """Generate prioritized recommendations based on vulnerabilities."""
443
+ recommendations = []
444
+ categories_seen = set()
445
+
446
+ # Sort by severity
447
+ severity_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
448
+ sorted_vulns = sorted(vulnerabilities, key=lambda v: severity_order.get(v.get("severity", "low"), 3))
449
+
450
+ for vuln in sorted_vulns:
451
+ cat = vuln.get("vulnerability_type", "unknown")
452
+ if cat not in categories_seen:
453
+ categories_seen.add(cat)
454
+ rec = _get_recommendation(cat)
455
+ severity = vuln.get("severity_level", "medium").upper()
456
+ recommendations.append(f"[{severity}] {cat}: {rec}")
457
+
458
+ if not recommendations:
459
+ recommendations.append("No critical vulnerabilities detected. Continue regular security review.")
460
+
461
+ return recommendations[:10] # Limit to top 10
462
+
463
+
464
+ def _generate_vulnerability_yara_rules(
465
+ vulnerabilities: list[dict],
466
+ filename: str,
467
+ dangerous_calls: list[dict]
468
+ ) -> list[str]:
469
+ """Generate YARA rules for detected vulnerabilities."""
470
+ rules = []
471
+
472
+ # Sanitize filename for rule name
473
+ safe_name = re.sub(r"[^a-zA-Z0-9]", "_", filename)
474
+
475
+ # Group by category
476
+ categories = {}
477
+ for vuln in vulnerabilities:
478
+ cat = vuln.get("vulnerability_type", "unknown")
479
+ if cat not in categories:
480
+ categories[cat] = []
481
+ categories[cat].append(vuln)
482
+
483
+ for category, vulns in categories.items():
484
+ if category in ["buffer_overflow", "command_injection", "code_injection"]:
485
+ apis = list(set(v.get("dangerous_api_name", "") for v in vulns))
486
+
487
+ rule = f'''rule vuln_{safe_name}_{category} {{
488
+ meta:
489
+ description = "Detects {category} vulnerability pattern in {filename}"
490
+ severity = "{vulns[0].get('severity', 'medium')}"
491
+ author = "Vulnerability Hunter (auto-generated)"
492
+ category = "{category}"
493
+
494
+ strings:
495
+ {_generate_yara_strings(apis)}
496
+
497
+ condition:
498
+ uint16(0) == 0x5A4D or uint32(0) == 0x464c457f and any of them
499
+ }}'''
500
+ rules.append(rule)
501
+
502
+ return rules
503
+
504
+
505
+ def _generate_yara_strings(apis: list[str]) -> str:
506
+ """Generate YARA string definitions for APIs."""
507
+ strings = []
508
+ for i, api in enumerate(apis[:10]): # Limit to 10
509
+ # ASCII version
510
+ strings.append(f'$api{i}_a = "{api}" ascii')
511
+ # Wide version (Windows)
512
+ strings.append(f'$api{i}_w = "{api}" wide')
513
+
514
+ return "\n ".join(strings)
515
+
516
+
517
+ # Note: VulnerabilityHunterPlugin has been removed.
518
+ # The vulnerability_hunter tool is now registered via MalwareToolsPlugin in malware/__init__.py.
519
+