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,214 @@
1
+ """YARA scanning tools for binary analysis with rule matching."""
2
+
3
+ from typing import Any, Protocol
4
+
5
+ from reversecore_mcp.core.decorators import log_execution
6
+ from reversecore_mcp.core.error_handling import handle_tool_errors
7
+ from reversecore_mcp.core.metrics import track_metrics
8
+ from reversecore_mcp.core.result import ToolResult, failure, success
9
+ from reversecore_mcp.core.security import validate_file_path
10
+ from reversecore_mcp.core.validators import validate_tool_parameters
11
+
12
+ # Global cache for compiled YARA rules: {file_path: (timestamp, compiled_rules)}
13
+ _YARA_RULES_CACHE: dict[str, tuple[float, Any]] = {}
14
+
15
+
16
+ class YaraStringMatchInstance(Protocol):
17
+ """Subset of yara.StringMatchInstance used by our formatter."""
18
+
19
+ offset: int | None
20
+ matched_data: bytes | None
21
+
22
+
23
+ class YaraStringMatch(Protocol):
24
+ """Subset of yara.StringMatch used by our formatter."""
25
+
26
+ identifier: str | None
27
+ instances: list[YaraStringMatchInstance] | None
28
+
29
+
30
+ class YaraMatch(Protocol):
31
+ """Subset of yara.Match used by our formatter."""
32
+
33
+ rule: str
34
+ namespace: str
35
+ tags: list[str]
36
+ meta: dict[str, Any]
37
+ strings: list[YaraStringMatch] | None
38
+
39
+
40
+ def _format_yara_match(match: YaraMatch) -> dict[str, Any]:
41
+ """
42
+ Format a YARA match result as a dictionary.
43
+
44
+ This helper function extracts match information and formats it
45
+ consistently. Supports both modern and legacy yara-python APIs.
46
+
47
+ Args:
48
+ match: YARA match object
49
+
50
+ Returns:
51
+ Dictionary with formatted match information
52
+ """
53
+ formatted_strings = []
54
+
55
+ # Check if match has strings attribute
56
+ match_strings = getattr(match, "strings", None)
57
+ if match_strings:
58
+ try:
59
+ # OPTIMIZATION: Cache isinstance check and reduce getattr calls
60
+ # Try modern API first (more common case)
61
+ for sm in match_strings:
62
+ identifier = getattr(sm, "identifier", None)
63
+ instances = getattr(sm, "instances", None)
64
+ if instances:
65
+ # Pre-cache the formatted string for reuse
66
+ for inst in instances:
67
+ offset = getattr(inst, "offset", None)
68
+ matched_data = getattr(inst, "matched_data", None)
69
+ # Convert matched_data to string (optimized with early check)
70
+ if matched_data is None:
71
+ data_str = None
72
+ else:
73
+ # Single isinstance check instead of repeated checks
74
+ data_str = (
75
+ matched_data.hex()
76
+ if isinstance(matched_data, bytes)
77
+ else str(matched_data)
78
+ )
79
+
80
+ formatted_strings.append(
81
+ {
82
+ "identifier": identifier,
83
+ "offset": int(offset) if offset is not None else None,
84
+ "matched_data": data_str,
85
+ }
86
+ )
87
+ except (AttributeError, TypeError):
88
+ # Fallback: older API may return tuples (offset, identifier, data)
89
+ formatted_strings = []
90
+ for t in match_strings:
91
+ if isinstance(t, (list, tuple)) and len(t) >= 3:
92
+ off, ident, data = t[0], t[1], t[2]
93
+ data_str = data.hex() if isinstance(data, bytes) else str(data)
94
+ formatted_strings.append(
95
+ {
96
+ "identifier": ident,
97
+ "offset": int(off) if off is not None else None,
98
+ "matched_data": data_str,
99
+ }
100
+ )
101
+
102
+ return {
103
+ "rule": match.rule,
104
+ "namespace": match.namespace,
105
+ "tags": match.tags,
106
+ "meta": match.meta,
107
+ "strings": formatted_strings,
108
+ }
109
+
110
+
111
+ @log_execution(tool_name="run_yara")
112
+ @track_metrics("run_yara")
113
+ @handle_tool_errors
114
+ def run_yara(
115
+ file_path: str,
116
+ rule_file: str,
117
+ timeout: int = 300,
118
+ ) -> ToolResult:
119
+ """Scan binaries against YARA rules via ``yara-python``."""
120
+
121
+ validate_tool_parameters(
122
+ "run_yara",
123
+ {"rule_file": rule_file, "timeout": timeout},
124
+ )
125
+ validated_file = validate_file_path(file_path)
126
+ validated_rule = validate_file_path(rule_file, read_only=True)
127
+
128
+ try:
129
+ import yara
130
+ except ImportError:
131
+ return failure(
132
+ "DEPENDENCY_MISSING",
133
+ "yara-python library is not installed",
134
+ hint="Install with: pip install yara-python",
135
+ )
136
+
137
+ timeout_error = getattr(yara, "TimeoutError", None)
138
+ generic_error = getattr(yara, "Error", None)
139
+
140
+ # Check cache for compiled rules
141
+ rule_path_str = str(validated_rule)
142
+ current_mtime = validated_rule.stat().st_mtime
143
+
144
+ rules = None
145
+ if rule_path_str in _YARA_RULES_CACHE:
146
+ cached_mtime, cached_rules = _YARA_RULES_CACHE[rule_path_str]
147
+ if cached_mtime == current_mtime:
148
+ rules = cached_rules
149
+
150
+ if rules is None:
151
+ try:
152
+ rules = yara.compile(filepath=rule_path_str)
153
+ # Update cache with size limit
154
+ if len(_YARA_RULES_CACHE) >= 100:
155
+ # Remove oldest entry (FIFO) to prevent unbounded growth
156
+ _YARA_RULES_CACHE.pop(next(iter(_YARA_RULES_CACHE)))
157
+ _YARA_RULES_CACHE[rule_path_str] = (current_mtime, rules)
158
+ except Exception as exc: # noqa: BLE001 - need yara-specific surface area
159
+ # Try fallback for non-ASCII paths on Windows
160
+ try:
161
+ # Read rule content and compile from source
162
+ rule_content = validated_rule.read_text(encoding="utf-8")
163
+ rules = yara.compile(source=rule_content)
164
+ if len(_YARA_RULES_CACHE) >= 100:
165
+ _YARA_RULES_CACHE.pop(next(iter(_YARA_RULES_CACHE)))
166
+ _YARA_RULES_CACHE[rule_path_str] = (current_mtime, rules)
167
+ except Exception:
168
+ # If fallback fails, report original error
169
+ if generic_error and isinstance(exc, generic_error):
170
+ return failure("YARA_ERROR", f"YARA error: {exc}")
171
+ raise
172
+
173
+ try:
174
+ matches = rules.match(str(validated_file), timeout=timeout)
175
+ except Exception as exc: # noqa: BLE001 - need to inspect yara-specific errors
176
+ # Check for timeout first
177
+ if timeout_error and isinstance(exc, timeout_error):
178
+ return failure(
179
+ "TIMEOUT",
180
+ f"YARA scan timed out after {timeout} seconds",
181
+ timeout_seconds=timeout,
182
+ details={"error": str(exc)},
183
+ )
184
+
185
+ # For any other error (including "Illegal byte sequence" on Windows),
186
+ # try fallback to memory scan if file size permits
187
+ file_size = 0
188
+ try:
189
+ file_size = validated_file.stat().st_size
190
+ except Exception:
191
+ pass
192
+
193
+ if file_size < 100 * 1024 * 1024:
194
+ try:
195
+ data = validated_file.read_bytes()
196
+ matches = rules.match(data=data, timeout=timeout)
197
+ except Exception as fallback_exc:
198
+ # If fallback fails, return the original error
199
+ if generic_error and isinstance(exc, generic_error):
200
+ return failure(
201
+ "YARA_ERROR",
202
+ f"Fallback failed: {fallback_exc}. Original: {exc}",
203
+ )
204
+ raise
205
+ else:
206
+ if generic_error and isinstance(exc, generic_error):
207
+ return failure("YARA_ERROR", f"YARA error: {exc}")
208
+ raise
209
+
210
+ if not matches:
211
+ return success({"matches": [], "match_count": 0})
212
+
213
+ results = [_format_yara_match(match) for match in matches]
214
+ return success({"matches": results, "match_count": len(matches)})
@@ -0,0 +1,19 @@
1
+ """
2
+ Patch Explainer module - Backward compatibility alias.
3
+
4
+ This module was moved to common/patch_explainer.
5
+ """
6
+
7
+ # Re-export everything from common.patch_explainer
8
+ from reversecore_mcp.tools.common.patch_explainer import *
9
+ from reversecore_mcp.tools.common.patch_explainer import (
10
+ explain_patch,
11
+ _generate_explanation,
12
+ _generate_diff_snippet,
13
+ )
14
+
15
+ __all__ = [
16
+ "explain_patch",
17
+ "_generate_explanation",
18
+ "_generate_diff_snippet",
19
+ ]
@@ -0,0 +1,13 @@
1
+ """Radare2 tools package."""
2
+ from reversecore_mcp.tools.radare2.radare2_mcp_tools import Radare2ToolsPlugin
3
+ from reversecore_mcp.tools.radare2 import r2_analysis
4
+
5
+ # Backward compatibility re-exports for legacy imports
6
+ from reversecore_mcp.tools.analysis import static_analysis
7
+
8
+ __all__ = [
9
+ "Radare2ToolsPlugin",
10
+ "r2_analysis",
11
+ # Backward compatibility
12
+ "static_analysis",
13
+ ]