# nsis

A pure Rust parser for [NSIS (NullSoft Scriptable Install System)](https://nsis.sourceforge.io/)
installer binaries. Provides typed access to all internal structures — from
PE overlay detection through decompressed headers to individual bytecode
instructions and embedded files.

Built for **malware analysis** and **reverse engineering**.

## Features

- Parse PE overlay to locate NSIS data appended after PE sections
- Decompress header blocks (deflate, bzip2, LZMA) in solid and non-solid modes
- Iterate sections, pages, bytecode entries, language tables, and embedded files
- Decode NSIS string tables (ANSI, Unicode, Jim Park fork encoding) with variable and shell folder resolution
- Version-aware opcode lookup across NSIS 1.x, 2.x, 3.x, and the Park Unicode fork
- High-level analysis iterators for security-relevant operations:
  plugin calls, process execution, registry modifications, shortcut creation, uninstaller stubs
- Extract and decompress embedded files
- Zero-copy view types — the only heap allocations are for decompressed data and decoded strings
- `#![deny(unsafe_code)]`

## Quick start

```rust
use nsis::NsisInstaller;

let data = std::fs::read("installer.exe").unwrap();
let installer = NsisInstaller::from_bytes(&data).unwrap();

println!("Version:     {:?}", installer.version());
println!("Compression: {:?} ({:?})", installer.compression(), installer.compression_mode());
println!("Encoding:    {:?}", installer.string_encoding());
println!("Sections:    {}", installer.section_count());
println!("Entries:     {}", installer.entry_count());
```

## Analysis iterators

The high-level API surfaces operations that are commonly relevant during
malware triage:

```rust
// Plugin DLL calls (System.dll, nsDialogs.dll, etc.)
for call in installer.plugin_calls() {
    let call = call.unwrap();
    println!("Plugin: {} -> {}", call.dll().unwrap(), call.function().unwrap());
}

// Process execution (Exec, ExecWait, ShellExec)
for cmd in installer.exec_commands() {
    println!("{:?}", cmd.unwrap());
}

// Registry operations (read, write, delete)
for op in installer.registry_ops() {
    println!("{:?}", op.unwrap());
}

// Shortcut creation and embedded uninstallers
for shortcut in installer.shortcuts() { /* ... */ }
for uninst in installer.uninstallers() { /* ... */ }
```

## File extraction

```rust
for file in installer.files() {
    let file = file.unwrap();
    let name = file.name().unwrap();
    println!("{}: {} bytes (compressed)", name, file.data().len());

    // Decompress the file data
    let content = file.decompress().unwrap();
    std::fs::write(format!("out/{name}"), &content).unwrap();
}
```

## Dump example

The included `dump` example prints a full analysis of an installer and
optionally extracts embedded files:

```bash
cargo run --example dump -- installer.exe
cargo run --example dump -- installer.exe --extract out/
```

## Minimum Rust version

1.85 (edition 2024)

## License

Apache-2.0
