EricZimmerman / EricZimmerman/LECmd
JSON/CSV output omits EnvironmentVariableDataBlock contents — target is unrecoverable for some LNKs
- Dominant language
- C#
- Stars
- 347
- Forks
- 33
- PR merge metrics
- No merged PRs in 30d
Description
Version: LECmd 2026.5.0 (net9)
Summary
For LNK files where the target path exists only in the EnvironmentVariableDataBlock, the JSON and CSV output contain no target path at all. `ExtraBlocksPresent `reports that the block exists, but its contents are not written to either format. The console output shows the value correctly, so this appears to be an output-serialization gap rather than a parsing problem.
Reproduction
A Control Panel shortcut (system-shipped, benign — used here only because it's a clean, easily reproduced example of the structure):
LECmd.exe --json . --pretty -f 907aee15304e.lnk
JSON output:
```
json
{
"SourceFile": "C:\\tools\\EZSuite\\net9\\907aee15304e.lnk",
"SourceModified": "2012-07-25T20:19:48.2602134+00:00",
"WorkingDirectory": "%windir%\\system32",
"HeaderFlags": "HasName, HasWorkingDir, HasArguments, HasIconLocation, IsUnicode, ForceNoLinkInfo, HasExpString, PreferEnvironmentPath",
"Arguments": "shell32.dll,Control_RunDLL",
"ExtraBlocksPresent": "PropertyStoreDataBlock, EnvironmentVariableDataBlock"
}
```
Console output for the same file:
```
>> Environment variable data block
Environment variables: %SystemRoot%\system32\rundll32.exe
```
The value is also visible in a hex view of the file at the expected offset.
Why this matters
The header flags on this file include `ForceNoLinkInfo`, `HasExpString `and `PreferEnvironmentPath`, so there is no LinkInfo structure and consequently no `LocalPath`. The EnvironmentVariableDataBlock is the only place the target is recorded. The JSON therefore reports the arguments (shell32.dll,Control_RunDLL) but not the executable they are passed to.
This shape is not rare, and it is used by malicious LNKs that reach `rundll32.exe`, `mshta.exe` and similar via the environment-variable path. In automated pipelines that consume the CSV or JSON, such a file appears to have no target at all — and there is no way to distinguish "the LNK had no target" from "the target was in a block the output doesn't carry."
The requested change is not conditional on those flags: the block's contents should be written whenever the block is present, since it is also useful when a `LocalPath `exists (the two can differ).
Worth noting the TrackerDataBlock is already promoted to real fields (`MachineID`, `MachineMACAddress`, `TrackerCreatedOn`), so there's precedent in the output format for surfacing block contents
Happy to test a build against LNKs that I have found missing this info
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the LECmd.exe JSON and CSV output paths and reproduce the issue using the provided command and LNK. Trace how EnvironmentVariableDataBlock contents are handled compared with TrackerDataBlock fields, then verify that both formats include the block contents while preserving console output and any existing LocalPath; test against the supplied Control Panel shortcut.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 70/100