mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

经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行) 功能影响:零破坏性,保持所有业务逻辑不变 这是基于业务需求分析的精准重构,消除真正多余的部分, 保持系统架构合理性和向后兼容性。
277 lines
6.7 KiB
Go
277 lines
6.7 KiB
Go
package local
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/shadow1ng/fscan/common"
|
|
)
|
|
|
|
// KeyloggerPlugin 键盘记录插件 - Linus式简化版本
|
|
//
|
|
// 设计哲学:直接实现,删除过度设计
|
|
// - 删除复杂的继承体系
|
|
// - 直接实现键盘记录功能
|
|
// - 保持原有功能逻辑
|
|
type KeyloggerPlugin struct {
|
|
name string
|
|
outputFile string
|
|
isRunning bool
|
|
stopChan chan struct{}
|
|
keyBuffer []string
|
|
bufferMutex sync.RWMutex
|
|
}
|
|
|
|
// NewKeyloggerPlugin 创建键盘记录插件
|
|
func NewKeyloggerPlugin() *KeyloggerPlugin {
|
|
outputFile := common.KeyloggerOutputFile
|
|
if outputFile == "" {
|
|
outputFile = "keylog.txt"
|
|
}
|
|
|
|
return &KeyloggerPlugin{
|
|
name: "keylogger",
|
|
outputFile: outputFile,
|
|
stopChan: make(chan struct{}),
|
|
keyBuffer: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
// GetName 实现Plugin接口
|
|
func (p *KeyloggerPlugin) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
|
|
// Scan 执行键盘记录 - 直接实现
|
|
func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
|
|
var output strings.Builder
|
|
|
|
output.WriteString("=== 键盘记录 ===\n")
|
|
output.WriteString(fmt.Sprintf("输出文件: %s\n", p.outputFile))
|
|
output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS))
|
|
|
|
// 检查输出文件权限
|
|
if err := p.checkOutputFilePermissions(); err != nil {
|
|
output.WriteString(fmt.Sprintf("输出文件权限检查失败: %v\n", err))
|
|
return &ScanResult{
|
|
Success: false,
|
|
Output: output.String(),
|
|
Error: err,
|
|
}
|
|
}
|
|
|
|
// 检查平台要求
|
|
if err := p.checkPlatformRequirements(); err != nil {
|
|
output.WriteString(fmt.Sprintf("平台要求检查失败: %v\n", err))
|
|
return &ScanResult{
|
|
Success: false,
|
|
Output: output.String(),
|
|
Error: err,
|
|
}
|
|
}
|
|
|
|
// 启动键盘记录
|
|
err := p.startKeylogging(ctx)
|
|
if err != nil {
|
|
output.WriteString(fmt.Sprintf("键盘记录失败: %v\n", err))
|
|
return &ScanResult{
|
|
Success: false,
|
|
Output: output.String(),
|
|
Error: err,
|
|
}
|
|
}
|
|
|
|
// 输出结果
|
|
output.WriteString("✓ 键盘记录已完成\n")
|
|
output.WriteString(fmt.Sprintf("捕获事件数: %d\n", len(p.keyBuffer)))
|
|
output.WriteString(fmt.Sprintf("日志文件: %s\n", p.outputFile))
|
|
|
|
common.LogSuccess(fmt.Sprintf("键盘记录完成,捕获了 %d 个键盘事件", len(p.keyBuffer)))
|
|
|
|
return &ScanResult{
|
|
Success: true,
|
|
Output: output.String(),
|
|
Error: nil,
|
|
}
|
|
}
|
|
|
|
// startKeylogging 启动键盘记录
|
|
func (p *KeyloggerPlugin) startKeylogging(ctx context.Context) error {
|
|
p.isRunning = true
|
|
defer func() {
|
|
p.isRunning = false
|
|
}()
|
|
|
|
// 根据平台启动相应的键盘记录
|
|
var err error
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
err = p.startWindowsKeylogging(ctx)
|
|
case "linux":
|
|
err = p.startLinuxKeylogging(ctx)
|
|
case "darwin":
|
|
err = p.startDarwinKeylogging(ctx)
|
|
default:
|
|
err = fmt.Errorf("不支持的平台: %s", runtime.GOOS)
|
|
}
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("键盘记录失败: %v", err)
|
|
}
|
|
|
|
// 保存到文件
|
|
if err := p.saveKeysToFile(); err != nil {
|
|
common.LogError(fmt.Sprintf("保存键盘记录失败: %v", err))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// checkOutputFilePermissions 检查输出文件权限
|
|
func (p *KeyloggerPlugin) checkOutputFilePermissions() error {
|
|
file, err := os.OpenFile(p.outputFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
|
if err != nil {
|
|
return fmt.Errorf("无法创建输出文件 %s: %v", p.outputFile, err)
|
|
}
|
|
file.Close()
|
|
return nil
|
|
}
|
|
|
|
// checkPlatformRequirements 检查平台特定要求
|
|
func (p *KeyloggerPlugin) checkPlatformRequirements() error {
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
return p.checkWindowsRequirements()
|
|
case "linux":
|
|
return p.checkLinuxRequirements()
|
|
case "darwin":
|
|
return p.checkDarwinRequirements()
|
|
default:
|
|
return fmt.Errorf("不支持的平台: %s", runtime.GOOS)
|
|
}
|
|
}
|
|
|
|
// addKeyToBuffer 添加按键到缓冲区
|
|
func (p *KeyloggerPlugin) addKeyToBuffer(key string) {
|
|
p.bufferMutex.Lock()
|
|
defer p.bufferMutex.Unlock()
|
|
|
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
|
entry := fmt.Sprintf("[%s] %s", timestamp, key)
|
|
p.keyBuffer = append(p.keyBuffer, entry)
|
|
}
|
|
|
|
// saveKeysToFile 保存键盘记录到文件
|
|
func (p *KeyloggerPlugin) saveKeysToFile() error {
|
|
p.bufferMutex.RLock()
|
|
defer p.bufferMutex.RUnlock()
|
|
|
|
if len(p.keyBuffer) == 0 {
|
|
common.LogInfo("没有捕获到键盘输入")
|
|
return nil
|
|
}
|
|
|
|
file, err := os.OpenFile(p.outputFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
|
if err != nil {
|
|
return fmt.Errorf("无法打开输出文件: %v", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// 写入头部信息
|
|
header := fmt.Sprintf("=== 键盘记录日志 ===\n")
|
|
header += fmt.Sprintf("开始时间: %s\n", time.Now().Format("2006-01-02 15:04:05"))
|
|
header += fmt.Sprintf("平台: %s\n", runtime.GOOS)
|
|
header += fmt.Sprintf("捕获事件数: %d\n", len(p.keyBuffer))
|
|
header += fmt.Sprintf("========================\n\n")
|
|
|
|
if _, err := file.WriteString(header); err != nil {
|
|
return fmt.Errorf("写入头部信息失败: %v", err)
|
|
}
|
|
|
|
// 写入键盘记录
|
|
for _, entry := range p.keyBuffer {
|
|
if _, err := file.WriteString(entry + "\n"); err != nil {
|
|
return fmt.Errorf("写入键盘记录失败: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// 平台特定的键盘记录实现 - 简化版本,仅做演示
|
|
func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error {
|
|
// Windows平台键盘记录实现
|
|
// 在实际实现中需要使用Windows API
|
|
p.addKeyToBuffer("演示键盘记录 - Windows平台")
|
|
|
|
// 模拟记录一段时间
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(5 * time.Second):
|
|
// 模拟结束
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error {
|
|
// Linux平台键盘记录实现
|
|
// 在实际实现中需要访问/dev/input/event*设备
|
|
p.addKeyToBuffer("演示键盘记录 - Linux平台")
|
|
|
|
// 模拟记录一段时间
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(5 * time.Second):
|
|
// 模拟结束
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error {
|
|
// macOS平台键盘记录实现
|
|
// 在实际实现中需要使用Core Graphics框架
|
|
p.addKeyToBuffer("演示键盘记录 - macOS平台")
|
|
|
|
// 模拟记录一段时间
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(5 * time.Second):
|
|
// 模拟结束
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// 平台特定的要求检查 - 简化版本
|
|
func (p *KeyloggerPlugin) checkWindowsRequirements() error {
|
|
// Windows平台要求检查
|
|
return nil
|
|
}
|
|
|
|
func (p *KeyloggerPlugin) checkLinuxRequirements() error {
|
|
// Linux平台要求检查
|
|
return nil
|
|
}
|
|
|
|
func (p *KeyloggerPlugin) checkDarwinRequirements() error {
|
|
// macOS平台要求检查
|
|
return nil
|
|
}
|
|
|
|
// 注册插件
|
|
func init() {
|
|
RegisterLocalPlugin("keylogger", func() Plugin {
|
|
return NewKeyloggerPlugin()
|
|
})
|
|
} |