parent
3adba7a09d
commit
5ffce43b21
206
cmd/safe/safe.go
206
cmd/safe/safe.go
|
|
@ -3,7 +3,6 @@ package safe
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sysmonitord/internal/config"
|
||||
"sysmonitord/internal/scanner/file"
|
||||
"sysmonitord/internal/scanner/process"
|
||||
|
|
@ -58,21 +57,19 @@ func interactiveSafe(cfg *config.Config) {
|
|||
dubiousFiles, err := storage.LoadDubiousFiles(dataDir, cfg.Storage.DubiousFileListFile)
|
||||
if err != nil {
|
||||
fmt.Printf("无法读取可疑文件列表: %v\n", err)
|
||||
return
|
||||
dubiousFiles = nil
|
||||
}
|
||||
if len(dubiousFiles) == 0 {
|
||||
fmt.Println("没有可疑文件需要处理。")
|
||||
return
|
||||
}
|
||||
|
||||
dubiousProcesses, err := storage.LoadDubiousProcesses(dataDir, cfg.Storage.DubiousProcessListFile)
|
||||
if err != nil {
|
||||
fmt.Printf("无法读取可疑进程列表: %v\n", err)
|
||||
return
|
||||
dubiousProcesses = nil
|
||||
}
|
||||
if len(dubiousProcesses) == 0 {
|
||||
fmt.Println("没有可疑进程需要处理。")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("\n╔══════════════════════════════════════════════╗")
|
||||
|
|
@ -93,10 +90,11 @@ func interactiveSafe(cfg *config.Config) {
|
|||
fmt.Println("╚══════════════════════════════════════════════╝")
|
||||
|
||||
fmt.Println("\n请选择操作:")
|
||||
fmt.Println("[1] 将以上可疑文件全部确认为安全 (移至白名单)")
|
||||
fmt.Println("[2] 将以上可疑进程全部确认为安全 (移至白名单)")
|
||||
fmt.Println("[3] 全部确认安全 (文件和进程)")
|
||||
// Todo: 支持逐个确认
|
||||
fmt.Println("[1] 逐个确认可疑文件")
|
||||
fmt.Println("[2] 逐个确认可疑进程")
|
||||
fmt.Println("[3] 将可疑文件全部确认为安全")
|
||||
fmt.Println("[4] 将可疑进程全部确认为安全")
|
||||
fmt.Println("[5] 全部确认安全 (文件和进程)")
|
||||
fmt.Println("[ESC] 退出不处理")
|
||||
fmt.Print("请输入选项: ")
|
||||
|
||||
|
|
@ -108,30 +106,54 @@ func interactiveSafe(cfg *config.Config) {
|
|||
|
||||
switch input {
|
||||
case "1":
|
||||
fmt.Println("正在处理...")
|
||||
if err := confirmFilesAsSafe(cfg, dubiousFiles); err != nil {
|
||||
fmt.Printf("处理失败: %v\n", err)
|
||||
conformed, unconfirmed := confirmFiles(dubiousFiles)
|
||||
if len(conformed) > 0 {
|
||||
fmt.Println("正在处理可疑文件...")
|
||||
if err := confirmFilesAsSafe(cfg, conformed); err != nil {
|
||||
fmt.Printf("确认文件安全失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("已将 %d 个文件移入白名单,%d 个文件仍为可疑\n", len(conformed), len(unconfirmed))
|
||||
}
|
||||
} else {
|
||||
fmt.Println("已将可疑文件移入白名单。")
|
||||
fmt.Println("没有文件被确认安全,所有文件仍为可疑。")
|
||||
}
|
||||
case "2":
|
||||
fmt.Println("正在处理...")
|
||||
if err := confirmProcessesAsSafe(cfg, dubiousProcesses); err != nil {
|
||||
fmt.Printf("处理失败: %v\n", err)
|
||||
conformed, unconfirmed := confirmProcesses(dubiousProcesses)
|
||||
if len(conformed) > 0 {
|
||||
fmt.Println("正在处理可疑进程...")
|
||||
if err := confirmProcessesAsSafe(cfg, conformed); err != nil {
|
||||
fmt.Printf("确认进程安全失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("已将 %d 个进程移入白名单,%d 个进程仍为可疑\n", len(conformed), len(unconfirmed))
|
||||
}
|
||||
} else {
|
||||
fmt.Println("已将可疑进程移入白名单。")
|
||||
fmt.Println("没有进程被确认安全,所有进程仍为可疑。")
|
||||
}
|
||||
case "3":
|
||||
fmt.Println("正在处理...")
|
||||
fmt.Println("正在将所有可疑文件确认为安全...")
|
||||
if err := confirmFilesAsSafe(cfg, dubiousFiles); err != nil {
|
||||
fmt.Printf("处理失败: %v\n", err)
|
||||
fmt.Printf("确认文件安全失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("已将可疑文件移入白名单。")
|
||||
fmt.Printf("已将 %d 个文件移入白名单\n", len(dubiousFiles))
|
||||
}
|
||||
case "4":
|
||||
fmt.Println("正在将所有可疑进程确认为安全...")
|
||||
if err := confirmProcessesAsSafe(cfg, dubiousProcesses); err != nil {
|
||||
fmt.Printf("确认进程安全失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("已将 %d 个进程移入白名单\n", len(dubiousProcesses))
|
||||
}
|
||||
case "5":
|
||||
fmt.Println("正在将所有可疑文件和进程确认为安全...")
|
||||
if err := confirmFilesAsSafe(cfg, dubiousFiles); err != nil {
|
||||
fmt.Printf("确认文件安全失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("已将 %d 个文件移入白名单\n", len(dubiousFiles))
|
||||
}
|
||||
if err := confirmProcessesAsSafe(cfg, dubiousProcesses); err != nil {
|
||||
fmt.Printf("处理失败: %v\n", err)
|
||||
fmt.Printf("确认进程安全失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("已将可疑进程移入白名单。")
|
||||
fmt.Printf("已将 %d 个进程移入白名单\n", len(dubiousProcesses))
|
||||
}
|
||||
case "ESC":
|
||||
fmt.Println("已取消操作。")
|
||||
|
|
@ -142,15 +164,11 @@ func interactiveSafe(cfg *config.Config) {
|
|||
}
|
||||
|
||||
func confirmProcessesAsSafe(cfg *config.Config, processes []storage.DubiousProcessInfo) error {
|
||||
dataDir := cfg.Storage.DataDir
|
||||
whiteListPath := filepath.Join(dataDir, cfg.Storage.ProcessSystemFile)
|
||||
// dubiousFile := filepath.Join(dataDir, cfg.Storage.DubiousProcessListFile)
|
||||
|
||||
f, err := os.OpenFile(whiteListPath, os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法打开白名单文件: %v", err)
|
||||
if len(processes) == 0 {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
dataDir := cfg.Storage.DataDir
|
||||
|
||||
var toWhitelist []process.ProcessInfo
|
||||
for _, proc := range processes {
|
||||
|
|
@ -162,30 +180,23 @@ func confirmProcessesAsSafe(cfg *config.Config, processes []storage.DubiousProce
|
|||
}
|
||||
|
||||
if err := storage.AppendProcessToWhitelist(toWhitelist, dataDir, cfg.Storage.ProcessSystemFile); err != nil {
|
||||
return fmt.Errorf("更新白名单失败: %v", err)
|
||||
return fmt.Errorf("更新进程白名单失败: %v", err)
|
||||
}
|
||||
|
||||
logger.Log.Debug("已将可疑进程移入白名单", zap.Int("count", len(toWhitelist)))
|
||||
|
||||
// Todo: 逐个删除条目
|
||||
if err := storage.RemoveDubiousProcesses(dataDir, cfg.Storage.DubiousProcessListFile, []storage.DubiousProcessInfo{}); err != nil {
|
||||
if err := storage.RemoveDubiousProcesses(dataDir, cfg.Storage.DubiousProcessListFile, processes); err != nil {
|
||||
return fmt.Errorf("删除可疑进程列表失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func confirmFilesAsSafe(cfg *config.Config, files []storage.DubiousFileInfo) error {
|
||||
dataDir := cfg.Storage.DataDir
|
||||
whiteListPath := filepath.Join(dataDir, cfg.Storage.FileSystemFile)
|
||||
// dubiousFile := filepath.Join(dataDir, cfg.Storage.DubiousFileListFile)
|
||||
|
||||
f, err := os.OpenFile(whiteListPath, os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法打开白名单文件: %v", err)
|
||||
if len(files) == 0 {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
dataDir := cfg.Storage.DataDir
|
||||
|
||||
var toWhitelist []file.FileInfo
|
||||
for _, f := range files {
|
||||
|
|
@ -201,10 +212,113 @@ func confirmFilesAsSafe(cfg *config.Config, files []storage.DubiousFileInfo) err
|
|||
|
||||
logger.Log.Debug("已将可疑文件移入白名单", zap.Int("count", len(toWhitelist)))
|
||||
|
||||
// Todo: 逐个删除条目
|
||||
if err := storage.RemoveDubiousFiles(dataDir, cfg.Storage.DubiousFileListFile, []storage.DubiousFileInfo{}); err != nil {
|
||||
if err := storage.RemoveDubiousFiles(dataDir, cfg.Storage.DubiousFileListFile, files); err != nil {
|
||||
return fmt.Errorf("删除可疑文件列表失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func confirmFiles(files []storage.DubiousFileInfo) (confirmed []storage.DubiousFileInfo, unconfirmed []storage.DubiousFileInfo) {
|
||||
if len(files) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
fmt.Println("\n╔══════════════════════════════════════════════╗")
|
||||
fmt.Println("║ 逐个确认可疑文件 ║")
|
||||
fmt.Println("╠══════════════════════════════════════════════╣")
|
||||
fmt.Println("║ [y] 确认安全 [n] 仍为可疑 [q] 退出 ║")
|
||||
fmt.Println("╚══════════════════════════════════════════════╝")
|
||||
|
||||
for i, file := range files {
|
||||
fmt.Printf("\n[%d/%d] 文件路径: %s\n", i+1, len(files), file.Path)
|
||||
fmt.Printf(" 哈希值: %s\n", file.Hash)
|
||||
fmt.Printf(" 发现时间: %s\n", file.DiscoveredAt)
|
||||
fmt.Print(" 选择 [y/n/q]: ")
|
||||
|
||||
input, err := readKeyWithESC()
|
||||
if err != nil {
|
||||
fmt.Printf("读取输入失败: %v,跳过此文件\n", err)
|
||||
unconfirmed = append(unconfirmed, file)
|
||||
continue
|
||||
}
|
||||
|
||||
switch input {
|
||||
case "y", "Y":
|
||||
fmt.Println("已确认安全")
|
||||
confirmed = append(confirmed, file)
|
||||
case "n", "N":
|
||||
fmt.Println("仍为可疑")
|
||||
unconfirmed = append(unconfirmed, file)
|
||||
case "q", "Q":
|
||||
fmt.Println("已退出确认")
|
||||
for j := i; j < len(files); j++ {
|
||||
unconfirmed = append(unconfirmed, files[j])
|
||||
}
|
||||
return confirmed, unconfirmed
|
||||
default:
|
||||
fmt.Println("无效输入,默认仍为可疑")
|
||||
unconfirmed = append(unconfirmed, file)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\n╔══════════════════════════════════════════════╗\n")
|
||||
fmt.Printf("║ 文件确认完成 ║\n")
|
||||
fmt.Printf("║ ✓ 确认安全: %d 个 ║\n", len(confirmed))
|
||||
fmt.Printf("║ ✗ 保留可疑: %d 个 ║\n", len(unconfirmed))
|
||||
fmt.Printf("╚══════════════════════════════════════════════╝\n")
|
||||
|
||||
return confirmed, unconfirmed
|
||||
}
|
||||
|
||||
func confirmProcesses(processes []storage.DubiousProcessInfo) (confirmed []storage.DubiousProcessInfo, unconfirmed []storage.DubiousProcessInfo) {
|
||||
if len(processes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
fmt.Println("\n╔══════════════════════════════════════════════╗")
|
||||
fmt.Println("║ 逐个确认可疑进程 ║")
|
||||
fmt.Println("╠══════════════════════════════════════════════╣")
|
||||
fmt.Println("║ [y] 确认安全 [n] 仍为可疑 [q] 退出 ║")
|
||||
fmt.Println("╚══════════════════════════════════════════════╝")
|
||||
|
||||
for i, proc := range processes {
|
||||
fmt.Printf("\n[%d/%d] 进程名称: %s\n", i+1, len(processes), proc.Name)
|
||||
fmt.Printf(" 路径: %s\n", proc.Path)
|
||||
fmt.Printf(" 哈希值: %s\n", proc.FileHash)
|
||||
fmt.Print(" 选择 [y/n/q]: ")
|
||||
|
||||
input, err := readKeyWithESC()
|
||||
if err != nil {
|
||||
fmt.Printf("读取输入失败: %v,跳过此进程\n", err)
|
||||
unconfirmed = append(unconfirmed, proc)
|
||||
continue
|
||||
}
|
||||
|
||||
switch input {
|
||||
case "y", "Y":
|
||||
fmt.Println("已确认安全")
|
||||
confirmed = append(confirmed, proc)
|
||||
case "n", "N":
|
||||
fmt.Println("仍为可疑")
|
||||
unconfirmed = append(unconfirmed, proc)
|
||||
case "q", "Q":
|
||||
fmt.Println("已退出确认")
|
||||
for j := i; j < len(processes); j++ {
|
||||
unconfirmed = append(unconfirmed, processes[j])
|
||||
}
|
||||
return confirmed, unconfirmed
|
||||
default:
|
||||
fmt.Println("无效输入,默认仍为可疑")
|
||||
unconfirmed = append(unconfirmed, proc)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\n╔══════════════════════════════════════════════╗\n")
|
||||
fmt.Printf("║ 进程确认完成 ║\n")
|
||||
fmt.Printf("║ ✓ 确认安全: %d 个 ║\n", len(confirmed))
|
||||
fmt.Printf("║ ✗ 保留可疑: %d 个 ║\n", len(unconfirmed))
|
||||
fmt.Printf("╚══════════════════════════════════════════════╝\n")
|
||||
|
||||
return confirmed, unconfirmed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,8 +180,28 @@ func AppendProcessToWhitelist(procs []process.ProcessInfo, dataDir string, proce
|
|||
return writer.Flush()
|
||||
}
|
||||
|
||||
func RemoveDubiousProcesses(dataDir string, dubiousProcessFile string, toKeep []DubiousProcessInfo) error {
|
||||
func RemoveDubiousProcesses(dataDir string, dubiousProcessFile string, toRemove []DubiousProcessInfo) error {
|
||||
filePath := filepath.Join(dataDir, dubiousProcessFile)
|
||||
|
||||
allProcs, err := LoadDubiousProcesses(dataDir, dubiousProcessFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("[storage]无法加载可疑进程记录文件%s: %w", filePath, err)
|
||||
}
|
||||
|
||||
toRemoveMap := make(map[string]bool)
|
||||
for _, proc := range toRemove {
|
||||
key := fmt.Sprintf("%s:%s", proc.Name, proc.Path)
|
||||
toRemoveMap[key] = true
|
||||
}
|
||||
|
||||
var toKeep []DubiousProcessInfo
|
||||
for _, proc := range allProcs {
|
||||
key := fmt.Sprintf("%s:%d", proc.Name, proc.PID)
|
||||
if !toRemoveMap[key] {
|
||||
toKeep = append(toKeep, proc)
|
||||
}
|
||||
}
|
||||
|
||||
if len(toKeep) == 0 {
|
||||
return os.Remove(filePath)
|
||||
}
|
||||
|
|
@ -194,6 +214,11 @@ func RemoveDubiousProcesses(dataDir string, dubiousProcessFile string, toKeep []
|
|||
|
||||
writer := bufio.NewWriter(f)
|
||||
|
||||
header := fmt.Sprintf("# 可疑进程记录 - 最后更新: %s\n", time.Now().Format("2006-01-02 15:04:05"))
|
||||
if _, err := writer.WriteString(header); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, proc := range toKeep {
|
||||
line := fmt.Sprintf("%s:%s:%s\n", proc.Name, proc.Path, proc.FileHash)
|
||||
if _, err := writer.WriteString(line); err != nil {
|
||||
|
|
@ -201,7 +226,15 @@ func RemoveDubiousProcesses(dataDir string, dubiousProcessFile string, toKeep []
|
|||
}
|
||||
}
|
||||
|
||||
return writer.Flush()
|
||||
if err := writer.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Log.Debug("[storage]已从可疑进程列表删除条目",
|
||||
zap.Int("deleted", len(toRemove)),
|
||||
zap.Int("remaining", len(toKeep)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SaveDubiousFiles(files DubiousFileInfo, dataDir string, dubiousFileName string) error {
|
||||
|
|
@ -243,8 +276,26 @@ func AppendFileToWhitelist(files []file.FileInfo, dataDir string, fileSystemFile
|
|||
return writer.Flush()
|
||||
}
|
||||
|
||||
func RemoveDubiousFiles(dataDir string, dubiousFileName string, toKeep []DubiousFileInfo) error {
|
||||
func RemoveDubiousFiles(dataDir string, dubiousFileName string, toRemove []DubiousFileInfo) error {
|
||||
filePath := filepath.Join(dataDir, dubiousFileName)
|
||||
|
||||
allFiles, err := LoadDubiousFiles(dataDir, dubiousFileName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("[storage]无法加载可疑文件记录文件%s: %w", filePath, err)
|
||||
}
|
||||
|
||||
toRemoveMap := make(map[string]bool)
|
||||
for _, file := range toRemove {
|
||||
toRemoveMap[file.Path] = true
|
||||
}
|
||||
|
||||
var toKeep []DubiousFileInfo
|
||||
for _, file := range allFiles {
|
||||
if !toRemoveMap[file.Path] {
|
||||
toKeep = append(toKeep, file)
|
||||
}
|
||||
}
|
||||
|
||||
if len(toKeep) == 0 {
|
||||
return os.Remove(filePath)
|
||||
}
|
||||
|
|
@ -257,6 +308,11 @@ func RemoveDubiousFiles(dataDir string, dubiousFileName string, toKeep []Dubious
|
|||
|
||||
writer := bufio.NewWriter(f)
|
||||
|
||||
header := fmt.Sprintf("# 可疑文件记录 - 最后更新: %s\n", time.Now().Format("2006-01-02 15:04:05"))
|
||||
if _, err := writer.WriteString(header); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, file := range toKeep {
|
||||
line := fmt.Sprintf("%s:%s:%s\n", file.Path, file.Hash, file.DiscoveredAt)
|
||||
if _, err := writer.WriteString(line); err != nil {
|
||||
|
|
@ -264,7 +320,15 @@ func RemoveDubiousFiles(dataDir string, dubiousFileName string, toKeep []Dubious
|
|||
}
|
||||
}
|
||||
|
||||
return writer.Flush()
|
||||
if err := writer.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Log.Debug("[storage]已从可疑文件列表删除条目",
|
||||
zap.Int("deleted", len(toRemove)),
|
||||
zap.Int("remaining", len(toKeep)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadDubiousFiles(dataDir string, dubiousFileName string) ([]DubiousFileInfo, error) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user