fscan/plugins/local/avdetect.go
ZacharyZcR 8f54702c02 refactor: 精准修复插件系统三个设计问题
经Linus式架构审计,发现并修复插件系统中的具体问题:

## 核心修复

### 1. 消除local插件GetPorts()方法冗余
- 删除21个local插件中无意义的GetPorts()方法
- 简化local.Plugin接口:移除端口概念
- 理由:本地插件不涉及网络,端口概念完全多余

### 2. 消除web插件GetPorts()方法冗余
- 删除2个web插件中无用的GetPorts()方法
- 简化web.WebPlugin接口:专注智能HTTP检测
- 理由:Web插件使用动态HTTP检测,预定义端口无价值

### 3. 统一插件命名规范
- 统一所有插件接口使用Name()方法(符合Go惯例)
- 消除GetName()与Name()不一致问题
- 简化适配器:不再需要方法名转换

## 技术改进

接口精简:
- local插件:GetName() + GetPorts() → Name()
- web插件:GetName() + GetPorts() → Name()
- services插件:GetName() → Name()(保留GetPorts(),业务必需)

代码减少:
- 删除23个无用GetPorts()方法
- 重命名52个Name()方法
- 简化3个插件接口定义

## 影响范围

修改文件:55个插件文件
代码变更:-155行 +61行(净减少94行)
功能影响:零破坏性,保持所有业务逻辑不变

这是基于业务需求分析的精准重构,消除真正多余的部分,
保持系统架构合理性和向后兼容性。
2025-08-26 20:38:39 +08:00

196 lines
4.6 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.

package local
import (
_ "embed"
"context"
"encoding/json"
"fmt"
"os/exec"
"runtime"
"strings"
"github.com/shadow1ng/fscan/common"
)
//go:embed auto.json
var avDatabase []byte
// AVProduct AV产品信息结构
type AVProduct struct {
Processes []string `json:"processes"`
URL string `json:"url"`
}
// AVDetectPlugin AV/EDR检测插件 - Linus式简化版本
//
// 设计哲学:"做一件事并做好" - 专注AV检测
// - 使用JSON数据库加载AV信息
// - 删除复杂的结果结构体
// - 跨平台支持,运行时适配
type AVDetectPlugin struct {
name string
avProducts map[string]AVProduct
}
// NewAVDetectPlugin 创建AV检测插件
func NewAVDetectPlugin() *AVDetectPlugin {
plugin := &AVDetectPlugin{
name: "avdetect",
avProducts: make(map[string]AVProduct),
}
// 加载AV数据库
if err := json.Unmarshal(avDatabase, &plugin.avProducts); err != nil {
common.LogError(fmt.Sprintf("加载AV数据库失败: %v", err))
} else {
common.LogInfo(fmt.Sprintf("加载了 %d 个AV产品信息", len(plugin.avProducts)))
}
return plugin
}
// GetName 实现Plugin接口
func (p *AVDetectPlugin) Name() string {
return p.name
}
// Scan 执行AV/EDR检测 - 直接、有效
func (p *AVDetectPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
var output strings.Builder
var detectedAVs []string
output.WriteString("=== AV/EDR检测 ===\n")
// 获取运行进程
processes := p.getRunningProcesses()
if len(processes) == 0 {
return &ScanResult{
Success: false,
Output: "无法获取进程列表",
Error: fmt.Errorf("进程列表获取失败"),
}
}
output.WriteString(fmt.Sprintf("扫描进程数: %d\n\n", len(processes)))
// 检测AV产品 - 使用JSON数据库
for avName, avProduct := range p.avProducts {
var foundProcesses []string
for _, avProcess := range avProduct.Processes {
for _, runningProcess := range processes {
// 简单字符串匹配,忽略大小写
if strings.Contains(strings.ToLower(runningProcess), strings.ToLower(avProcess)) {
foundProcesses = append(foundProcesses, runningProcess)
}
}
}
if len(foundProcesses) > 0 {
detectedAVs = append(detectedAVs, avName)
output.WriteString(fmt.Sprintf("✓ 检测到 %s:\n", avName))
for _, proc := range foundProcesses {
output.WriteString(fmt.Sprintf(" - %s\n", proc))
}
common.LogSuccess(fmt.Sprintf("检测到AV: %s (%d个进程)", avName, len(foundProcesses)))
output.WriteString("\n")
}
}
// 统计结果
output.WriteString("=== 检测结果 ===\n")
output.WriteString(fmt.Sprintf("检测到的AV产品: %d个\n", len(detectedAVs)))
if len(detectedAVs) > 0 {
output.WriteString("检测到的产品: " + strings.Join(detectedAVs, ", ") + "\n")
} else {
output.WriteString("未检测到已知的AV/EDR产品\n")
}
return &ScanResult{
Success: len(detectedAVs) > 0,
Output: output.String(),
Error: nil,
}
}
// getRunningProcesses 获取运行进程列表 - 跨平台适配
func (p *AVDetectPlugin) getRunningProcesses() []string {
var processes []string
switch runtime.GOOS {
case "windows":
processes = p.getWindowsProcesses()
case "linux", "darwin":
processes = p.getUnixProcesses()
default:
// 不支持的平台,返回空列表
return processes
}
return processes
}
// getWindowsProcesses 获取Windows进程 - 简化实现
func (p *AVDetectPlugin) getWindowsProcesses() []string {
var processes []string
// 使用tasklist命令
cmd := exec.Command("tasklist", "/fo", "csv", "/nh")
output, err := cmd.Output()
if err != nil {
return processes
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
// 解析CSV格式进程名在第一列
if strings.HasPrefix(line, "\"") {
parts := strings.Split(line, "\",\"")
if len(parts) > 0 {
processName := strings.Trim(parts[0], "\"")
if processName != "" {
processes = append(processes, processName)
}
}
}
}
return processes
}
// getUnixProcesses 获取Unix进程 - 简化实现
func (p *AVDetectPlugin) getUnixProcesses() []string {
var processes []string
// 使用ps命令
cmd := exec.Command("ps", "-eo", "comm")
output, err := cmd.Output()
if err != nil {
return processes
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" && line != "COMMAND" {
processes = append(processes, line)
}
}
return processes
}
// 注册插件
func init() {
RegisterLocalPlugin("avdetect", func() Plugin {
return NewAVDetectPlugin()
})
}