shadow1ng/fscan · error
local_pe_not_found
Error message
local_pe_not_found
What it means
WinServicePlugin.Scan stats the configured PE path to ensure the local file exists before comparing it with installed service binaries. If os.Stat fails, the plugin returns this localized 'local PE not found' error including the configured path. Service enumeration is skipped entirely.
Source
Thrown at plugins/local/winservice.go:34
)
type WinServicePlugin struct {
plugins.BasePlugin
}
func NewWinServicePlugin() *WinServicePlugin {
return &WinServicePlugin{
BasePlugin: plugins.NewBasePlugin("winservice"),
}
}
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"))}
}
if _, err := os.Stat(pePath); err != nil {
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))
services := []struct {
name string
display string
start string
}{
{fmt.Sprintf("WinDefendUpdate_%s", baseName), "Windows Defender Update Service", "auto"},
{fmt.Sprintf("SysHealthMon_%s", baseName), "System Health Monitor", "delayed-auto"},
}
var output strings.Builder
var successCount int
for _, svc := range services {View on GitHub (pinned to 95cc12e753)
Solutions
- Verify and correct the path stored in Config.WinPEFile.
- Use an absolute path and check existence (os.Stat) before invoking the plugin.
- Restore the file or re-point the config to a copy that exists locally.
- Check read permissions on the file's directory.
Example fix
// before
session.Config.WinPEFile = "./agent.exe" // not in CWD
// after
pe := "/home/analyst/samples/agent.exe"
if _, err := os.Stat(pe); err != nil { log.Fatal(err) }
session.Config.WinPEFile = pe Defensive patterns
Strategy: validation
Validate before calling
pePath := cfg.WinPEFile
if abs, err := filepath.Abs(pePath); err == nil { pePath = abs }
if _, err := os.Stat(pePath); err != nil {
return fmt.Errorf("service PE sample missing: %w", err)
} Try / catch
res := plugin.Scan(ctx, host, session)
if !res.Success {
if _, statErr := os.Stat(session.Config.WinPEFile); statErr != nil {
// file vanished; re-acquire sample and retry
}
} Prevention
- Stat the sample immediately before scanning, not only at config time.
- Keep samples outside AV-monitored directories or add exclusions.
- Store absolute paths in case configs.
When it happens
Trigger: Config.WinPEFile non-empty but the path does not resolve: nonexistent file, relative path against an unexpected CWD, removed/quarantined sample, or unreadable directory.
Common situations: Path typo; the sample was deleted after the config was written; running the tool under a different user/CWD; pointing to a network share that is offline.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/48a1f817b9d124b9.
Report an issue: GitHub.