Package Exports
- node-lief
- node-lief/lib/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (node-lief) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
LIEF Node.js Bindings
Node.js bindings for LIEF - the Library to Instrument Executable Formats.
Parse and manipulate binary executables (ELF, PE, Mach-O, etc.) from JavaScript/TypeScript with full access to LIEF's comprehensive API.
Features
- Format Support: ELF (Linux), PE (Windows), Mach-O (macOS/iOS)
- Binary Parsing: Automatically detect and parse binary format
- Symbol & Relocation Access: Read symbols, relocations, and section information
- Binary Modification: Patch addresses, modify sections, extend segments, and more
- Format-Agnostic API: Work with the generic Binary interface
- Format-Specific APIs: Access format-specific details (MachO segments, code signatures, etc.)
- TypeScript Support: Full type definitions included
- Prebuilt Binaries: Fast installation with prebuilt binaries for common platforms
Installation
pnpm install node-liefFor most platforms, prebuilt binaries will be automatically installed. If no prebuilt binary is available, the package will compile from source automatically.
Prerequisites
For prebuilt binaries (recommended):
- Node.js 14+
For building from source:
- Node.js 14+
- CMake 3.15+
- Ninja build system
- C++17 compatible compiler (GCC 7+, Clang 5+, MSVC 2017+)
- Git (for cloning LIEF submodule)
Quick Start
const LIEF = require('node-lief');
// Parse a binary file (auto-detects format)
const binary = LIEF.parse('/bin/ls');
console.log(`Format: ${binary.format}`); // 'ELF', 'PE', 'MachO', or 'UNKNOWN'
console.log(`Entrypoint: 0x${binary.entrypoint.toString(16)}`);
console.log(`PIE: ${binary.isPie}`);
console.log(`NX: ${binary.hasNx}`);
// Access sections
const sections = binary.sections();
sections.forEach(section => {
console.log(`Section: ${section.name} @ 0x${section.virtualAddress.toString(16)}`);
});
// Access symbols
const symbols = binary.symbols();
symbols.forEach(symbol => {
console.log(`Symbol: ${symbol.name} @ 0x${symbol.value.toString(16)}`);
});
// Get a specific symbol by name
const mainSymbol = binary.getSymbol('main');
if (mainSymbol) {
console.log(`main @ 0x${mainSymbol.value.toString(16)}`);
}
// Patch an address with new bytes
binary.patchAddress(0x1000n, [0x90, 0x90, 0x90]); // NOP sled
// Write modified binary
binary.write('./output');TypeScript Example
import * as LIEF from 'node-lief';
// Parse with auto-detection
const binary = LIEF.parse('/bin/ls');
// Type-safe access to properties
const entrypoint: bigint = binary.entrypoint;
const isPie: boolean = binary.isPie;
const format: 'ELF' | 'PE' | 'MachO' | 'UNKNOWN' = binary.format;
// Format-specific operations
if (binary.format === 'ELF') {
// ELF-specific code here
const elfBinary = binary as LIEF.ELF.Binary;
}
// Work with sections, symbols, and relocations
const sections: LIEF.Abstract.Section[] = binary.sections();
const symbols: LIEF.Abstract.Symbol[] = binary.symbols();
const relocations: LIEF.Abstract.Relocation[] = binary.relocations();
// Modify and write
binary.patchAddress(0x1000n, Buffer.from([0x90, 0x90]));
binary.write('./output');API Documentation
Main Functions
LIEF.parse(filename: string)
Parse a binary file and return format-specific binary object. Automatically detects the format and returns the appropriate type.
Returns: ELF.Binary | PE.Binary | MachO.Binary | Abstract.Binary
LIEF.MachO.parse(filename: string)
Parse a MachO file and return a FatBinary object (which may contain single or multiple architectures).
Returns: MachO.FatBinary
Abstract.Binary
Generic binary interface that works across all formats.
Properties
format: string- Binary format ('ELF', 'PE', 'MachO', 'UNKNOWN')entrypoint: bigint- Entry point addressisPie: boolean- Whether binary is position-independenthasNx: boolean- Whether binary has NX protectionheader: Header- Binary header information
Methods
sections(): Section[]- Get all sectionssymbols(): Symbol[]- Get all symbolsrelocations(): Relocation[]- Get all relocationssegments(): Segment[]- Get all segments (empty for Abstract, implemented for MachO)getSymbol(name: string): Symbol | null- Get a specific symbol by namepatchAddress(address: number | bigint, patch: Buffer | number[]): void- Patch bytes at addresswrite(outputPath: string): void- Write the binary to disk
Section
Represents a section in a binary.
name: string- Section nametype: string- Section typevirtualAddress: bigint- Virtual addresssize: bigint- Section size (read/write)virtualSize: bigint- Virtual size (read/write)fileOffset: bigint- Offset in fileoffset: bigint- File offset (alias)content: number[] | Buffer- Section content (read/write)
Symbol
Represents a symbol in a binary.
name: string- Symbol namevalue: bigint- Symbol value/addresssize: bigint- Symbol size
Relocation
Represents a relocation in a binary.
address: bigint- Relocation addresssize: number- Relocation size
Format-Specific Classes
ELF.Binary
ELF-specific binary class with all Abstract.Binary methods.
PE.Binary
PE (Windows) specific binary class with all Abstract.Binary methods.
MachO.Binary
MachO-specific binary class with additional methods:
hasCodeSignature: boolean- Whether the binary has a code signaturegetSegment(name: string): Segment | null- Get a segment by nameremoveSignature(): void- Remove code signatureextendSegment(segment: Segment, size: bigint | number): boolean- Extend a segment
MachO.Segment
Represents a MachO segment.
name: string- Segment nametype: string- Segment typevirtualAddress: bigint- Virtual addressvirtualSize: bigint- Virtual sizefileOffset: bigint- File offsetfileSize: bigint- File sizesections(): Section[]- Get sections in this segmentgetSection(name: string): Section | null- Get a section by name
MachO.FatBinary
Universal/Fat binary containing multiple architectures.
size(): number- Number of architecturesat(index: number): Binary | null- Get binary at indextake(index: number): Binary | null- Get and take ownership of binary at index
Logging
LIEF.logging.disable()- Disable LIEF logging outputLIEF.logging.enable()- Enable LIEF logging output
Building from Source
The package includes LIEF as a git submodule and uses a two-stage build process:
# Clone with submodules
git clone --recursive https://github.com/Piebald-AI/node-lief.git
cd node-lief
# Install dependencies
pnpm install
# Build (this runs both stages automatically)
pnpm buildBuild Process Details
Stage 1: Build LIEF library (
pnpm build:lief)- Runs
scripts/build-lief.sh - Uses CMake + Ninja to build LIEF C++ library
- Produces
lief-build/libLIEF.a(orLIEF.libon Windows) - Configured for minimal build (disables Python/Rust APIs, OAT, DEX, etc.)
- Runs
Stage 2: Build Node addon (
node-gyp rebuild)- Links against the pre-built LIEF static library
- Compiles C++ sources in
src/directory - Produces
build/Release/node_lief.node
Build Commands
# Full build (LIEF + addon)
pnpm build
# Clean build artifacts
pnpm clean
# Build only LIEF library
pnpm build:lief
# Create prebuilt binaries for distribution
pnpm prebuildifyBuild Requirements
- CMake 3.15+ with Ninja generator
- C++17 compiler with RTTI support enabled
- Git for LIEF submodule
- node-gyp for native addon compilation
The build is configured in:
binding.gyp- node-gyp configurationscripts/build-lief.sh- LIEF CMake configuration
Supported Node.js Versions
- Node.js 14+ (BigInt support required)
- Node.js 16+ (recommended)
- All current LTS versions
Platform Support
- Linux (x86-64, ARM64)
- macOS (Intel x86-64, Apple Silicon ARM64) - requires macOS 13.0+
- Windows (x86-64)
Prebuilt binaries are provided for common platforms via prebuildify. For unsupported platforms, the package will automatically compile from source.
Performance
The Node.js bindings are compiled to native code with minimal overhead:
- Binary parsing: Near C++ native performance
- Symbol/section enumeration: Fast iteration via N-API
- Memory efficient: Smart pointers ensure proper cleanup
- No serialization overhead: Direct access to LIEF's C++ objects
For production use cases:
- Parsing typical executables: < 100ms
- Large binaries (100MB+): A few seconds
- Comparable performance to LIEF's Python bindings
Advanced Usage
Working with MachO Fat Binaries
MachO files can contain multiple architectures. Use MachO.parse() to handle them:
const LIEF = require('node-lief');
// Parse as Fat binary
const fat = LIEF.MachO.parse('./universal-binary');
console.log(`Architectures: ${fat.size()}`);
// Access individual architectures
for (let i = 0; i < fat.size(); i++) {
const binary = fat.at(i);
console.log(`Arch ${i}: ${binary.format}`);
// Work with binary...
}Modifying Section Content
const binary = LIEF.parse('./binary');
const sections = binary.sections();
// Find and modify a section
const textSection = sections.find(s => s.name === '.text' || s.name === '__text');
if (textSection) {
// Read content
const content = textSection.content;
// Modify content (as array or Buffer)
const newContent = Buffer.from([0x90, 0x90, 0x90]);
textSection.content = newContent;
textSection.size = BigInt(newContent.length);
// Write modified binary
binary.write('./modified-binary');
}MachO Code Signature Removal
const binary = LIEF.MachO.parse('./signed-macho').at(0);
if (binary.hasCodeSignature) {
console.log('Removing code signature...');
binary.removeSignature();
binary.write('./unsigned-macho');
}Error Handling
const LIEF = require('node-lief');
try {
const binary = LIEF.parse('./binary');
// Perform operations
binary.patchAddress(0x1000n, [0x90, 0x90]);
binary.write('./output');
} catch (error) {
console.error('Error:', error.message);
// Handle parse errors, invalid addresses, I/O errors, etc.
}Current Limitations
This is an actively developed project. Current limitations:
- Format coverage: ELF, PE, and MachO are well-supported; OAT, DEX, VDEX, and ART are not included in the build
- API coverage: Core functionality implemented; some advanced LIEF features not yet exposed
- Debug info: DWARF and PDB parsing not yet implemented
- Async operations: Currently synchronous only; async API planned
- Streaming: No support for streaming large files; entire binary loaded into memory
Contributions welcome! See CLAUDE.md for development guidance.
Contributing
Contributions are welcome! This project is actively developed and there are many opportunities to expand functionality.
Priority Areas
- Format-specific APIs: Expose more ELF, PE, and MachO-specific features
- Debug information: DWARF and PDB parsing support
- Async operations: Add async/await API for I/O operations
- Documentation: Usage examples, tutorials, API docs
- Performance: Optimize hot paths, add benchmarks
Development Setup
# Clone with submodules
git clone --recursive https://github.com/Piebald-AI/node-lief.git
cd node-lief
# Install and build
pnpm install
pnpm build
# Make changes to src/...
# Rebuild
pnpm buildSee CLAUDE.md for detailed development guidelines and architecture documentation.
Project Structure
node-lief/
├── src/
│ ├── init.cpp # Module initialization
│ ├── abstract/ # Format-agnostic API
│ │ ├── binary.{h,cpp}
│ │ ├── section.{h,cpp}
│ │ ├── segment.{h,cpp}
│ │ └── symbol.{h,cpp}
│ ├── elf/ # ELF-specific
│ │ └── binary.{h,cpp}
│ ├── pe/ # PE-specific
│ │ └── binary.{h,cpp}
│ └── macho/ # MachO-specific
│ ├── binary.{h,cpp}
│ ├── fat_binary.{h,cpp}
│ └── parse.cpp
├── lib/
│ ├── index.js # Entry point
│ └── index.d.ts # TypeScript definitions
├── scripts/
│ └── build-lief.sh # LIEF build script
├── binding.gyp # node-gyp configuration
└── LIEF/ # Git submoduleAdding New Features
See CLAUDE.md for detailed instructions on:
- Adding new methods to existing classes
- Creating new wrapper classes
- Working with LIEF types
- Memory management patterns
- Error handling conventions
License
Apache License 2.0 (same as LIEF)
Related Projects
- LIEF Project - The underlying C++ library
- LIEF Documentation - Comprehensive LIEF docs
- LIEF GitHub - LIEF source code
- node-addon-api - N-API wrapper used by this project
Support and Resources
- Issues: Report bugs and request features on GitHub Issues
- Documentation: See CLAUDE.md, USAGE.md, and ARCHITECTURE.md
- Examples: Check USAGE.md and QUICK_START.md for usage examples
- LIEF Help: Refer to LIEF documentation for underlying functionality
Acknowledgments
This project is built on top of LIEF by Quarkslab. LIEF is a comprehensive library for parsing and manipulating executable formats, and this package aims to make that functionality easily accessible to the Node.js ecosystem.