Skip to content

Commit 298c13f

Browse files
committed
feat: Refactored AI verdict module for better modularity and efficiency, removed unnecessary code, and improved overall structure.
1 parent df077fa commit 298c13f

File tree

8 files changed

+253
-154
lines changed

8 files changed

+253
-154
lines changed

Main Files/modules/ai_verdict.py

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
"""
2+
AI Verdict Processing Module
3+
Author: Phantom0004 (Daryl Gatt)
4+
5+
Description:
6+
Handles AI-driven analysis of YARA scan results, providing structured and detailed insights into potential threats.
7+
This module interacts with an external AI model to generate contextual intelligence based on detected Indicators of Compromise (IoCs).
8+
9+
Features:
10+
- **AI-Powered Verdicts:** Sends YARA scan results to an advanced AI model for context-aware threat analysis.
11+
- **Terminal Adaptive Formatting:** Dynamically adjusts output formatting based on terminal capabilities (plain text or Markdown).
12+
- **API Communication Handling:** Manages API requests and response handling, ensuring robust connectivity.
13+
14+
Usage:
15+
- Pass structured YARA scan results to this module.
16+
- The AI model will process the structured IoC findings and return an actionable analysis.
17+
- Depending on terminal support, plain text and Markdown formatting will be selected.
18+
"""
19+
20+
from rich.console import Console
21+
from rich.markdown import Markdown
22+
from typing import Tuple
23+
import requests
24+
25+
class AIVerdict:
26+
"""
27+
Processes YARA scan results and interacts with an AI model for threat analysis.
28+
29+
This class:
30+
- Structures unstructured YARA scan results for AI-driven analysis.
31+
- Categorizes YARA rules into general file analysis and malware-specific classifications.
32+
- Formats AI-generated responses based on terminal support.
33+
- Manages API requests and error handling for AI communication.
34+
35+
Attributes:
36+
yara_results (list): The unstructured YARA scan results provided at initialization.
37+
console (Console): Rich console instance for handling terminal output formatting.
38+
"""
39+
40+
def __init__(self, structured_yara_results: list) -> dict:
41+
self.structured_yara_results = structured_yara_results
42+
self.console = Console()
43+
44+
def generate_api_request(self) -> dict:
45+
"""
46+
Generates a structured API request for the AI model based on YARA scan results.
47+
48+
Args:
49+
None
50+
51+
Returns:
52+
dict:
53+
- A dictionary containing the structured payload for the AI model.
54+
- The payload includes:
55+
- System and user messages with formatting based on terminal support.
56+
- YARA scan results formatted for analysis.
57+
- Model selection (`EleutherAI/gpt-j-6B`) for accurate responses.
58+
- A fixed seed value (`42`) to ensure deterministic output.
59+
"""
60+
61+
# Define prompt for AI model - plaintext for basic terminals and markdown for advanced terminals
62+
plaintext_prompt = """
63+
Format responses as plain text with concise paragraphs and line breaks, ensuring maximum compatibility with all terminal environments.
64+
Avoid any Markdown, JSON, or structured formatting—just simple, unadorned text.
65+
"""
66+
markdown_prompt = """
67+
Format responses with rich Markdown formatting to enhance clarity, structure, and visual appeal.
68+
Incorporate headings, bullet lists, code blocks, and other Markdown elements to produce well-organized, visually engaging output suitable for terminal display.
69+
"""
70+
71+
# Payload varies depending on terminal support for advanced formatting
72+
payload = {
73+
"messages": [
74+
{
75+
"role": "system",
76+
"content": (
77+
"You are 'MORPHEUS_IQ', an advanced cybersecurity expert in malware analysis."
78+
"Provide precise and actionable insights from IoCs and signature findings, avoiding speculation, repetition, or hallucinations."
79+
"Keep responses short and terminal-friendly, summarizing only critical details for quick analysis."
80+
f"{markdown_prompt if self.supports_advanced_formatting() else plaintext_prompt}"
81+
"Ensure output is clear, well-structured, and formatted for immediate readability in a technical environment."
82+
)
83+
},
84+
{
85+
"role": "user",
86+
"content": (
87+
"Analyze the provided scan results and deliver concise, actionable insights based on matched YARA signatures."
88+
f"\nScan Output: {str(self.structured_yara_results)}"
89+
)
90+
}
91+
],
92+
# Utalizes a high paramater model for more accurate results
93+
"model": "EleutherAI/gpt-j-6B",
94+
# This seed value ensures that the results are mostly deterministic
95+
"seed": 42
96+
}
97+
98+
return payload
99+
100+
def supports_advanced_formatting(self) -> bool:
101+
"""
102+
Checks if the terminal supports advanced formatting for markdown rendering.
103+
104+
Args:
105+
None
106+
107+
Returns:
108+
bool:
109+
- True if the terminal supports advanced formatting.
110+
- False otherwise.
111+
- This is determined by checking if the console is a terminal
112+
and if a color system is available.
113+
"""
114+
115+
return self.console.is_terminal and self.console.color_system is not None
116+
117+
def format_string_to_markdown(self, ai_verdict_output) -> None:
118+
"""
119+
Renders the AI-generated verdict as Markdown in the terminal.
120+
121+
Args:
122+
ai_verdict_output (str): The AI-generated analysis output to be formatted and displayed.
123+
124+
Returns:
125+
None:
126+
- Outputs the formatted AI response directly to the console.
127+
- Uses the `Markdown` class to render the response for enhanced readability.
128+
- Requires a terminal that supports rich text formatting.
129+
- If the terminal does not support advanced formatting, consider using plain text output.
130+
"""
131+
132+
self.console.print(Markdown(ai_verdict_output.strip()))
133+
134+
@staticmethod
135+
def send_api_request(payload: dict) -> Tuple[str, str]:
136+
"""
137+
Sends a POST request to the Pollinations API with the provided payload.
138+
139+
Args:
140+
payload (dict): The JSON-formatted data to be sent in the API request.
141+
142+
Returns:
143+
Tuple[str, str]:
144+
- The API response text and a status indicator.
145+
- If successful (`200 OK`), returns the API response text and `"success"`.
146+
- If the request times out, returns an error message and `"fail"`.
147+
- If a connection failure occurs, returns an error message detailing the issue and `"fail"`.
148+
- If an unknown exception occurs, returns a generic error message and `"fail"`.
149+
- If the API is offline (non-200 response), returns an appropriate message and `"fail"`.
150+
"""
151+
152+
# Send POST request to Pollinations API
153+
try:
154+
response = requests.post("https://text.pollinations.ai/", headers={"Content-Type": "application/json"}, json=payload)
155+
except requests.exceptions.Timeout:
156+
return "[-] API Endpoint Timed Out! Please try again at a later time.", "fail"
157+
except requests.exceptions.RequestException as error:
158+
return f"[-] Critical Connection Failure. Unable to connect to API - Error : {error}", "fail"
159+
except Exception as error:
160+
return f"[-] An Unknown Error has Occured - Error : {error}", "fail"
161+
162+
# Handle API response
163+
if response.status_code == 200:
164+
return response.text, "success"
165+
else:
166+
return f"[-] API Endpoint seems to be offline ... Please try again at a later time.", "fail"

Main Files/modules/virus_total.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,15 @@
2121

2222
try:
2323
import vt
24+
import requests
2425
from termcolor import colored
2526
except ModuleNotFoundError:
2627
exit(f"'virus_total.py' Library Error -> Please install all requirements via the 'requirements.txt' file with PIP")
2728

28-
import hashlib
29-
import requests
29+
from urllib.parse import urlparse, quote
30+
import hashlib
3031
import json
3132
import os
32-
import urllib.parse
33-
from urllib.parse import urlparse
3433

3534
class VirusTotalAPI:
3635
def __init__ (self, choice="1", data="placeholder", API_KEY="", client_obj=""):
@@ -368,7 +367,7 @@ def extract_behaviour_techniques_of_file(self):
368367

369368
# Rescan URL if any fail arises
370369
def rescan_url(self):
371-
data = urllib.parse.quote(self.data, safe='')
370+
data = quote(self.data, safe='')
372371

373372
# May not always work, but if it does, a re-scan will be submitted
374373
self.send_api_request_using_requests(f"urls/{data}/analyse")

Main Files/modules/yara_analysis.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,11 @@
1616
"""
1717

1818
import os
19+
import yara
1920
import concurrent.futures
2021
import threading
2122
from typing import Union, List
22-
try:
23-
import yara
24-
from termcolor import colored
25-
except Exception as err:
26-
if "libyara" in str(err):
27-
print("\nLibyara not found in your 'Yara' installation. Please try uninstall all python dependencies and re-install them.")
28-
exit("\nIf all else fails, open an issue on Morpheus with your details.")
29-
else:
30-
exit(f"'yara_analysis.py' Library Error -> Error on Import : {err}")
23+
from termcolor import colored
3124

3225
# Parent class which handles the core of this file
3326
class BaseDetection:
@@ -124,17 +117,12 @@ def identify_matches(self, yara_object:yara.Rules) -> Union[List[yara.Match], st
124117
def output_yara_matches(yara_match:yara.Match) -> None:
125118
if yara_match:
126119
for match in yara_match:
127-
# Required Variables
128120
tags = f"Matched Tags: {str(match.tags)}" if match.tags else ""
129121
metadata = f"Rule Description: {str(match.meta['description'])}" if match.meta["description"] else ""
130122
print(' ' * 80, end='\r') # Clears reminants from the dynamic printing
131-
132-
if "KRYPTOS" in str(match):
133-
# Detect for KRYPTOS ransomware
134-
print(f'[+] KRYPTOS RANSOMWARE DETECTED: {colored(str(match), attrs=["bold"])}')
135-
else:
136-
# Detect for any other malware
137-
print(f"[+] Matched Rule: '{colored(str(match), 'green', attrs=['bold'])}'"+" "+tags)
123+
124+
# Detect for any other malware
125+
print(f"[+] Matched Rule: '{colored(str(match), 'green', attrs=['bold'])}'"+" "+tags)
138126

139127
# Metadata Matches
140128
print(colored(metadata.capitalize(), "yellow"))

0 commit comments

Comments
 (0)