shadow1ng/fscan · error
local_pe_not_found
Error message
local_pe_not_found
What it means
WinRegistryPlugin.Scan stats the path in session.Config.WinPEFile to confirm the local PE file exists before parsing registry autoruns. If os.Stat fails (file missing, bad path, no permission), it returns this localized error with the path interpolated. The plugin does not touch the registry unless the file is present locally.
Source
Thrown at plugins/local/winregistry.go:34
)
type WinRegistryPlugin struct {
plugins.BasePlugin
}
func NewWinRegistryPlugin() *WinRegistryPlugin {
return &WinRegistryPlugin{
BasePlugin: plugins.NewBasePlugin("winregistry"),
}
}
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"))}
}
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))
entries := []struct {
key string
name string
desc string
}{
{`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
var successCount int
View on GitHub (pinned to 95cc12e753)
Solutions
- Verify the file exists at the configured path (ls/Test-Path) and correct Config.WinPEFile.
- Use an absolute path so the result does not depend on the process working directory.
- Check read permissions on the file and its parent directories.
- Re-download or restore the PE sample if it was removed.
Example fix
// before
session.Config.WinPEFile = "samples/implant.dll" // CWD differs -> not found
// after
abs, _ := filepath.Abs("samples/implant.dll")
if _, err := os.Stat(abs); err != nil { log.Fatal(err) }
session.Config.WinPEFile = abs Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(cfg.WinPEFile); err != nil {
return fmt.Errorf("PE file %q not accessible: %w", cfg.WinPEFile, err)
} Try / catch
res := plugin.Scan(ctx, host, session)
if !res.Success {
var peErr *os.PathError
if errors.As(res.Error, &peErr) { /* handle missing file */ }
} Prevention
- Use absolute paths for sample files in configs.
- Stat the file right after loading config to fail fast.
- Keep samples in a stable, permission-correct directory; watch for AV quarantine.
When it happens
Trigger: Config.WinPEFile is non-empty but os.Stat(pePath) returns an error: the file does not exist at that path, the path is misspelled/relative to the wrong working directory, or the stat is blocked by permissions.
Common situations: Typo in the PE file path; running the tool from a different CWD than expected with a relative path; the sample file was deleted/moved after configuration; pointing at a path on a drive that is not mounted.
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/d7839ec203200808.
Report an issue: GitHub.