//go:build windows package cleaner import ( "fmt" "os" "os/exec" "path/filepath" "strings" "syscall" "time" "github.com/shadow1ng/fscan/common" ) // cleanSystemTraces 清理Windows系统痕迹 func (p *CleanerPlugin) cleanSystemTraces() map[string]interface{} { report := make(map[string]interface{}) var cleaned []string // 1. 清理Windows事件日志 if eventLogs := p.cleanWindowsEventLogs(); len(eventLogs) > 0 { cleaned = append(cleaned, eventLogs...) report["event_logs"] = eventLogs } // 2. 清理预取文件 if prefetchFiles := p.cleanPrefetchFiles(); len(prefetchFiles) > 0 { cleaned = append(cleaned, prefetchFiles...) report["prefetch_files"] = prefetchFiles } // 3. 清理注册表痕迹 if registryKeys := p.cleanRegistryTraces(); len(registryKeys) > 0 { cleaned = append(cleaned, registryKeys...) report["registry_keys"] = registryKeys } // 4. 清理最近文档记录 if recentDocs := p.cleanRecentDocuments(); len(recentDocs) > 0 { cleaned = append(cleaned, recentDocs...) report["recent_documents"] = recentDocs } // 5. 清理Windows临时文件 if tempFiles := p.cleanWindowsTempFiles(); len(tempFiles) > 0 { cleaned = append(cleaned, tempFiles...) report["temp_files"] = tempFiles } p.cleanupStats["system_entries"] += len(cleaned) report["total_cleaned"] = len(cleaned) return report } // cleanWindowsEventLogs 清理Windows事件日志 func (p *CleanerPlugin) cleanWindowsEventLogs() []string { var cleaned []string // 尝试清理应用程序日志中的相关条目 logs := []string{"Application", "System", "Security"} for _, logName := range logs { // 使用wevtutil清理日志 cmd := exec.Command("wevtutil", "cl", logName) cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} if err := cmd.Run(); err != nil { common.LogDebug(fmt.Sprintf("清理 %s 日志失败 (权限不足): %v", logName, err)) } else { cleaned = append(cleaned, fmt.Sprintf("Windows Event Log: %s", logName)) common.LogSuccess(fmt.Sprintf("已清理Windows事件日志: %s", logName)) } } return cleaned } // cleanPrefetchFiles 清理预取文件 func (p *CleanerPlugin) cleanPrefetchFiles() []string { var cleaned []string prefetchDir := "C:\\Windows\\Prefetch" if _, err := os.Stat(prefetchDir); os.IsNotExist(err) { return cleaned } // 查找fscan相关的预取文件 entries, err := os.ReadDir(prefetchDir) if err != nil { common.LogDebug(fmt.Sprintf("无法访问预取目录 (权限不足): %v", err)) return cleaned } for _, entry := range entries { if entry.IsDir() { continue } filename := strings.ToUpper(entry.Name()) if strings.Contains(filename, "FSCAN") { prefetchFile := filepath.Join(prefetchDir, entry.Name()) if err := os.Remove(prefetchFile); err != nil { common.LogDebug(fmt.Sprintf("删除预取文件失败: %v", err)) } else { cleaned = append(cleaned, prefetchFile) common.LogSuccess(fmt.Sprintf("已删除预取文件: %s", entry.Name())) } } } return cleaned } // cleanRegistryTraces 清理注册表痕迹 func (p *CleanerPlugin) cleanRegistryTraces() []string { var cleaned []string // 清理UserAssist注册表项 if userAssist := p.cleanUserAssistRegistry(); len(userAssist) > 0 { cleaned = append(cleaned, userAssist...) } // 清理MRU(最近使用)记录 if mru := p.cleanMRURegistry(); len(mru) > 0 { cleaned = append(cleaned, mru...) } return cleaned } // cleanUserAssistRegistry 清理UserAssist注册表 func (p *CleanerPlugin) cleanUserAssistRegistry() []string { var cleaned []string // UserAssist键路径 keyPaths := []string{ "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}\\Count", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}\\Count", } for _, keyPath := range keyPaths { // 查询注册表项 cmd := exec.Command("reg", "query", keyPath) cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} output, err := cmd.Output() if err != nil { continue } // 查找fscan相关条目并删除 lines := strings.Split(string(output), "\n") for _, line := range lines { if strings.Contains(strings.ToUpper(line), "FSCAN") { // 提取值名称 parts := strings.Fields(line) if len(parts) > 0 { valueName := parts[0] // 删除注册表值 delCmd := exec.Command("reg", "delete", keyPath, "/v", valueName, "/f") delCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} if err := delCmd.Run(); err != nil { common.LogDebug(fmt.Sprintf("删除注册表项失败: %v", err)) } else { cleaned = append(cleaned, fmt.Sprintf("Registry: %s\\%s", keyPath, valueName)) common.LogSuccess(fmt.Sprintf("已删除UserAssist记录: %s", valueName)) } } } } } return cleaned } // cleanMRURegistry 清理MRU注册表记录 func (p *CleanerPlugin) cleanMRURegistry() []string { var cleaned []string // MRU键路径 mruKeys := []string{ "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU", } for _, keyPath := range mruKeys { // 这里可以添加更复杂的MRU清理逻辑 // 由于安全考虑,暂时只记录路径 common.LogDebug(fmt.Sprintf("检查MRU路径: %s", keyPath)) } return cleaned } // cleanRecentDocuments 清理最近文档记录 func (p *CleanerPlugin) cleanRecentDocuments() []string { var cleaned []string // 获取用户目录 userProfile := os.Getenv("USERPROFILE") if userProfile == "" { return cleaned } // 最近文档目录 recentDir := filepath.Join(userProfile, "AppData", "Roaming", "Microsoft", "Windows", "Recent") entries, err := os.ReadDir(recentDir) if err != nil { common.LogDebug(fmt.Sprintf("无法访问最近文档目录: %v", err)) return cleaned } for _, entry := range entries { if entry.IsDir() { continue } filename := strings.ToLower(entry.Name()) if strings.Contains(filename, "fscan") || strings.Contains(filename, "result") { recentFile := filepath.Join(recentDir, entry.Name()) if err := os.Remove(recentFile); err != nil { common.LogDebug(fmt.Sprintf("删除最近文档失败: %v", err)) } else { cleaned = append(cleaned, recentFile) common.LogSuccess(fmt.Sprintf("已删除最近文档: %s", entry.Name())) } } } return cleaned } // cleanWindowsTempFiles 清理Windows临时文件 func (p *CleanerPlugin) cleanWindowsTempFiles() []string { var cleaned []string // 临时目录 tempDirs := []string{ os.Getenv("TEMP"), os.Getenv("TMP"), "C:\\Windows\\Temp", } for _, tempDir := range tempDirs { if tempDir == "" { continue } entries, err := os.ReadDir(tempDir) if err != nil { continue } for _, entry := range entries { if entry.IsDir() { continue } filename := strings.ToLower(entry.Name()) if strings.Contains(filename, "fscan") || strings.Contains(filename, "tmp") { tempFile := filepath.Join(tempDir, entry.Name()) // 检查文件是否太新(可能正在使用) if info, err := entry.Info(); err == nil { if time.Since(info.ModTime()) < 5*time.Minute { continue } } if err := os.Remove(tempFile); err != nil { common.LogDebug(fmt.Sprintf("删除临时文件失败: %v", err)) } else { cleaned = append(cleaned, tempFile) common.LogSuccess(fmt.Sprintf("已删除临时文件: %s", entry.Name())) } } } } return cleaned } // cleanNetworkTraces 清理网络痕迹 func (p *CleanerPlugin) cleanNetworkTraces() map[string]interface{} { report := make(map[string]interface{}) var cleaned []string // 1. 清理DNS缓存 cmd := exec.Command("ipconfig", "/flushdns") cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} if err := cmd.Run(); err != nil { common.LogDebug(fmt.Sprintf("清理DNS缓存失败: %v", err)) } else { cleaned = append(cleaned, "DNS Cache") common.LogSuccess("已清理DNS缓存") } // 2. 清理ARP缓存 arpCmd := exec.Command("arp", "-d", "*") arpCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} if err := arpCmd.Run(); err != nil { common.LogDebug(fmt.Sprintf("清理ARP缓存失败: %v", err)) } else { cleaned = append(cleaned, "ARP Cache") common.LogSuccess("已清理ARP缓存") } report["network_caches"] = cleaned report["total_cleaned"] = len(cleaned) return report } // createWindowsSelfDestruct 创建Windows自毁脚本 func (p *CleanerPlugin) createWindowsSelfDestruct() map[string]interface{} { report := make(map[string]interface{}) // 创建批处理自毁脚本 batchScript := fmt.Sprintf(`@echo off timeout /t 2 /nobreak > nul del /f /q "%s" 2>nul del /f /q "%%~f0" 2>nul exit`, p.currentExecutable) scriptPath := filepath.Join(p.workingDirectory, "cleanup.bat") if err := os.WriteFile(scriptPath, []byte(batchScript), 0644); err != nil { common.LogError(fmt.Sprintf("创建自毁脚本失败: %v", err)) report["status"] = "failed" report["error"] = err.Error() } else { // 异步执行自毁脚本 go func() { time.Sleep(1 * time.Second) cmd := exec.Command(scriptPath) cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} cmd.Start() }() report["status"] = "scheduled" report["script_path"] = scriptPath common.LogInfo("已创建自毁脚本,将在退出后执行") } return report } // prepareSelfDestruction 准备自毁 func (p *CleanerPlugin) prepareSelfDestruction() map[string]interface{} { return p.createWindowsSelfDestruct() }