shadow1ng/fscan · error

local_invalid_pe

Error message

local_invalid_pe

What it means

After confirming the PE file exists, WinSchTaskPlugin.Scan checks its extension: only .exe and .dll are accepted because scheduled-task actions must reference executable images. Any other extension (.bin, .ps1, .sys, no extension) produces this localized 'invalid PE' error with the path interpolated.

Source

Thrown at plugins/local/winschtask.go:38

}

func NewWinSchTaskPlugin() *WinSchTaskPlugin {
	return &WinSchTaskPlugin{
		BasePlugin: plugins.NewBasePlugin("winschtask"),
	}
}

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"))}
	}
	if _, err := os.Stat(pePath); err != nil {
		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))}
	}

	absPath, _ := filepath.Abs(pePath)
	baseName := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))

	tasks := []struct {
		name     string
		schedule string
		modifier string
	}{
		{fmt.Sprintf("WindowsUpdateCheck_%s", baseName), "DAILY", "1"},
		{fmt.Sprintf("SystemSecurityScan_%s", baseName), "ONLOGON", ""},
		{fmt.Sprintf("MaintenanceTask_%s", baseName), "ONSTART", ""},
		{fmt.Sprintf("BackgroundService_%s", baseName), "HOURLY", "2"},
	}

	var output strings.Builder
	var successCount int

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Configure a path to an actual .exe or .dll file.
  2. Rename/copy the sample with an .exe or .dll extension only if it genuinely is a PE image; do not rename non-PE files.
  3. If you need to scan scripts or drivers, use the appropriate plugin rather than the schtask PE matcher.

Example fix

// before
session.Config.WinPEFile = "C:\\samples\\payload.bin" // ext not allowed
// after
session.Config.WinPEFile = "C:\\samples\\payload.dll" // valid PE extension
p.Scan(ctx, host, session)
Defensive patterns

Strategy: validation

Validate before calling

ext := strings.ToLower(filepath.Ext(cfg.WinPEFile))
if ext != ".exe" && ext != ".dll" {
    return fmt.Errorf("WinPEFile must be .exe or .dll, got %q", ext)
}

Prevention

When it happens

Trigger: session.Config.WinPEFile points to an existing file whose lowercased filepath.Ext is neither ".exe" nor ".dll", e.g. a raw payload with no extension, a .sys driver, or a script file.

Common situations: Pointing the plugin at a shellcode/payload blob without an extension; mistakenly configuring a script (.ps1/.bat) or driver (.sys) where a PE image is required; case-only extensions are fine (handled via strings.ToLower), but files like 'agent.exe.bak' are not.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/2a58d8de1c9acd6d. Report an issue: GitHub.