Releases: BinFlip/nsis-rs
Releases · BinFlip/nsis-rs
v0.3.0
[0.3.0] - 2026-06-03
Added
NsisInstaller::builder()returning aNsisInstallerBuilderfor configuring
a parse, plusNsisInstallerBuilder::max_decompressed_size()to set the
decompression budget.NsisInstaller::from_bytes()is retained as a
convenience that parses with default limits.NsisInstaller::max_decompressed_size()accessor and the
NsisInstaller::DEFAULT_MAX_DECOMPRESSED_SIZEconstant (64 MiB).decompress::DecodeLimit, an enum that makes the three real decode intents
explicit:Exact(n)(known size — stop atn, ignore trailing input),
Capped(n)(unknown size — decode to end-of-stream, error if it exceeds
n), andTruncate(n)(unknown size — decode to end-of-stream, stop atn
without error). Includes asize()accessor.Error::OutputTooLarge { limit }, returned when aCappedstream would
expand past its budget.
Changed
- Breaking: decompression budgets are now configurable instead of guessed.
The previousmax(compressed_size * 10, 64 MiB)heuristic — used for embedded
files, the solid file-data stream, and uninstaller overlays — is replaced by a
single budget threaded fromNsisInstaller::builder().max_decompressed_size(). - Breaking:
decompress::decompress_blocknow takes a singlelimit: DecodeLimitargument in place of the previousmax_output: usizeand
expected_size: Option<usize>parameters. - Breaking:
decompress::{decompress_deflate, decompress_bzip2, decompress_lzma}now takelimit: DecodeLimitin place of their
max_output/expected_sizeparameters. - Breaking:
Errorgained theOutputTooLargevariant; exhaustive matches
onErrormust handle it. - Over-budget extracted artifacts (files, uninstallers) now fail with
Error::OutputTooLargeinstead of being silently truncated, so callers no
longer receive partial data reported as success. - The LZMA decoder is now bounded during decompression via a size-limited
writer rather than decoding fully and truncating afterward.
Fixed
- Extract LZMA non-solid embedded files correctly. Per-file LZMA streams carry
no stored uncompressed size and terminate with an end-of-stream marker;
passing a fixed expected size madelzma-rsreject the marker
("Expected unpacked size of N but decompressed to M"), so every file in
affected installers was dropped. Unknown-size streams now rely on the EOS
marker. - Apply the same end-of-stream fix to the uninstaller-overlay decode path,
which carried the identical latent defect.
v0.2.1
Fixed
- Handle packed NSIS installers whose
FirstHeaderis structurally valid but
not 512-byte aligned relative to the PE overlay, as seen in Adload samples. - Report out-of-bounds
EW_EXTRACTFILEpayloads as iterator errors instead
of exposing malformed file records as empty extracted files.
v0.2.0
Added
NsisInstaller::format_entry(&Entry) -> Stringfor rendering an opcode
mnemonic plus decoded parameters as a script-like line.NsisInstaller::format_entry_params(&Entry) -> Stringfor consumers that
need reusable opcode-aware parameter formatting without reimplementing the
string/variable/jump decoding rules.NsisInstaller::script_analysis()for script-level control-flow analysis,
including roots, functions, basic blocks, edges, entry-to-block mapping, and
diagnostics for invalid targets.- Symbol-aware formatting via
format_entry_with_analysis()and
format_entry_params_with_analysis(), which annotate jump and call targets
with names fromScriptAnalysis.
Changed
- The
dumpexample now uses the crate-provided instruction formatting API. - The
dumpexample uses script analysis symbols when rendering control-flow
targets. - Opcode metadata now matches NSIS operand layouts more closely for stack,
UI, execution, registry, and file I/O instructions.
Fixed
EW_PUSHPOPformatting now treatsparam0as a variable forPopand as a
string forPush, preventing variable IDs from being decoded as offsets into
unrelated strings such asProgramFilesDir.- Corrected high-level accessor layouts for
ShellExecOpandRegDelete. - Corrected several opcode parameter layouts and types, including
EW_GETFULLPATHNAME,EW_INTOP,EW_INTFMT,EW_FINDWINDOW,
EW_SENDMESSAGE,EW_GETDLGITEM,EW_SHELLEXEC,EW_DELREG,EW_FOPEN,
EW_FSEEK, andEW_FINDFIRST.
v0.1.2
Added
fmt::Displayimplementations for the public diagnostic enums so
consumers no longer needformat!("{:?}", ...):CompressionMethod→"deflate","bzip2","lzma","none".CompressionMode→"solid","non-solid".StringEncoding→"ANSI","Unicode","Park".NsisVersion→"NSIS 1","NSIS 2","NSIS 3","NSIS Park".RegValueType→"REG_SZ","REG_EXPAND_SZ","REG_BINARY",
"REG_DWORD","REG_MULTI_SZ","REG_UNKNOWN(N)".
Callbackenum (src/installer/callback.rs) covering the ten
common-header callback slots (OnInit,OnInstSuccess,
OnInstFailed,OnUserAbort,OnGuiInit,OnGuiEnd,
OnMouseOverSection,OnVerifyInstDir,OnSelChange,
OnRebootFailed). Provides:Callback::ALL— all ten variants in common-header order.Callback::name()— canonical NSIS script name (e.g.".onInit").Callback::index()— slot index (0..10) into the common-header
callback array.fmt::Display— delegates toname().
NsisInstaller::callback(Callback) -> Option<usize>— generic
accessor that returns the entry index for any callback slot,
complementing the existing per-callbackon_init()/on_inst_success()
/ etc. methods.- All standard
EW_*opcode constants are re-exported at the crate root,
so upstream analysis crates can match opcode numbers without importing
the internalopcodemodule. Section::contains_entry(usize) -> bool— returnstruewhen the
given entry index falls within the section's[code, code+code_size)
range. Treats negativecode/code_sizeas zero, so consumers no
longer need defensive.max(0)casts before doing range checks.NsisInstaller::section_contains_entry(section_idx, entry_idx) -> bool
— convenience wrapper that resolves the section by index and applies
Section::contains_entry.
Changed
- The clippy panic-prevention lint set
(unwrap_used,expect_used,panic,arithmetic_side_effects,
indexing_slicing) is now declareddenyin
Cargo.toml [lints.clippy], so the policy holds regardless of the
consuming workspace. Previously onlymissing_docsandunsafe_code
were denied (insrc/lib.rs). - Triage and clearance of the 310 lint violations exposed by the new
policy. Affected files (paths relative tosrc/):
addressmap.rs,decompress/{bzip2,lzma,mod}.rs,
header/{blockheader,commonheader,firstheader,mod}.rs,
installer/{analysis,files,nsisinstaller}.rs,
nsis/{ctlcolors,entry,langtable,page,section}.rs,
opcode/mod.rs,
strings/{ansi,mod,park,unicode}.rs,
util.rs.
Patterns applied:&[u8]indexing →.get(...)withOption/Resultpropagation.- Offset/size arithmetic →
checked_add/checked_sub/
saturating_*. .unwrap()/.expect()on parse steps →?-propagated
Errorarms.
Tests retain the convenience ofunwrap/expect/panicvia the
cfg_attr(test, allow(...))escape hatch insrc/lib.rs.
Fixed
- Carried forward from in-progress work on
main: park opcode mapping
correction and uninstaller data extraction (see commit1778513).
v0.1.1
v0.1.0 — Initial release
Parse and inspect NSIS installer binaries from pure safe Rust.
Highlights:
Complete NSIS format support: deflate, LZMA, bzip2 × solid/non-solid
ANSI, Unicode, and Park string encodings
Zero-copy file extraction with decompression
Malware analysis iterators: plugin calls, exec commands, registry ops,
shortcuts, uninstallers with recursive parsing
71 opcodes with typed parameter annotations
All callbacks exposed (onInit is the #1 malware indicator)
175 tests across 8 self-built fixtures
No unsafe code, no panics, fully documented