A full-featured TypeScript library for reading and writing ELF (Executable and Linkable Format) files. This library provides comprehensive support for both 32-bit and 64-bit ELF files with proper handling of endianness, section headers, program headers, and section data.
- ✅ Unified Interface: Single API for both 32-bit and 64-bit ELF files
- ✅ Multi-architecture Support: ARM64, PowerPC, x86-64, x86, and more
- ✅ Endianness Support: Both little-endian and big-endian files
- ✅ Complete ELF Support: Headers, program headers, section headers, and data
- ✅ String Table Parsing: Section name resolution
- ✅ TypeScript Type Safety: Comprehensive type definitions with bigint support
- ✅ Perfect Fidelity: Byte-for-byte identical read/write operations
- ✅ Robust Error Handling: Proper validation and bounds checking
- ✅ Comprehensive Testing: Real-world ELF files from multiple architectures
- ✅ Memory Efficient: Uses bigint for all numeric fields to support both architectures
npm install astarionimport { ElfReader } from 'astarion';
import { readFileSync } from 'fs';
// Read an ELF file from disk
const buffer = readFileSync('path/to/executable').buffer;
const reader = new ElfReader(buffer);
const elf = reader.read();
// Check ELF class
if (elf.header.ident.class === ElfClass.ELFCLASS32) {
console.log('32-bit ELF file');
} else if (elf.header.ident.class === ElfClass.ELFCLASS64) {
console.log('64-bit ELF file');
}
// Access header information
console.log('Entry point:', elf.header.entry);
console.log('Machine type:', elf.header.machine);
console.log('Number of program headers:', elf.header.phnum);
console.log('Number of section headers:', elf.header.shnum);
// Access section names
for (let i = 0; i < elf.sectionHeaders.length; i++) {
const sectionName = reader.getSectionName(elf, i);
console.log(`Section ${i}: ${sectionName}`);
}import { ElfWriter, ElfClass, ElfData, ElfVersion, ElfOsAbi, ElfType, ElfMachine } from 'astarion';
// Create a simple ELF structure
const elf = {
header: {
ident: {
mag0: 0x7f,
mag1: 0x45,
mag2: 0x4c,
mag3: 0x46,
class: ElfClass.ELFCLASS64,
data: ElfData.ELFDATA2LSB,
version: ElfVersion.EV_CURRENT,
osabi: ElfOsAbi.ELFOSABI_LINUX,
abiversion: 0,
pad: new Uint8Array(7)
},
type: ElfType.ET_EXEC,
machine: ElfMachine.EM_X86_64,
version: 1,
entry: 0x400000n,
phoff: 64n,
shoff: 1024n,
flags: 0,
ehsize: 64,
phentsize: 56,
phnum: 1,
shentsize: 64,
shnum: 2,
shstrndx: 1
},
programHeaders: [
{
type: ProgramHeaderType.PT_LOAD,
flags: ProgramHeaderFlags.PF_R | ProgramHeaderFlags.PF_X,
offset: 0n,
vaddr: 0x400000n,
paddr: 0x400000n,
filesz: 1024n,
memsz: 1024n,
align: 0x1000n
}
],
sectionHeaders: [
{
name: 0,
type: SectionHeaderType.SHT_NULL,
flags: 0n,
addr: 0n,
offset: 0n,
size: 0n,
link: 0,
info: 0,
addralign: 0n,
entsize: 0n
},
{
name: 1,
type: SectionHeaderType.SHT_STRTAB,
flags: 0n,
addr: 0n,
offset: 1024n,
size: 10n,
link: 0,
info: 0,
addralign: 1n,
entsize: 0n
}
],
sectionData: new Map([
[1, new Uint8Array([0, 46, 115, 104, 115, 116, 114, 0, 0, 0])] // ".shstr\0"
])
};
const writer = new ElfWriter();
const buffer = writer.write(elf);
// Write to file
import { writeFileSync } from 'fs';
writeFileSync('output.elf', Buffer.from(buffer));Reads ELF files from ArrayBuffer.
Constructor:
new ElfReader(buffer: ArrayBuffer)
Methods:
read(): Elf- Parses the ELF file and returns an Elf objectgetSectionName(elf: Elf, sectionIndex: number): string- Gets the name of a section by index
Writes ELF objects to ArrayBuffer.
Constructor:
new ElfWriter()
Methods:
write(elf: Elf): ArrayBuffer- Serializes an Elf object to ArrayBuffer
Unified ELF file structure that supports both 32-bit and 64-bit files:
header: ElfHeaderprogramHeaders: ProgramHeader[]sectionHeaders: SectionHeader[]sectionData: Map<number, Uint8Array>
The ELF class (32-bit or 64-bit) is determined by the header.ident.class field. All numeric fields use bigint to support both architectures seamlessly.
Unified ELF header structure for both 32-bit and 64-bit files:
ident: ElfIdenttype: ElfTypemachine: ElfMachineversion: numberentry: bigintphoff: bigintshoff: bigintflags: numberehsize: numberphentsize: numberphnum: numbershentsize: numbershnum: numbershstrndx: number
All address and offset fields use bigint to support both 32-bit and 64-bit architectures. The actual size used when reading/writing depends on the ELF class.
ELF identification structure:
mag0: number- Magic number byte 0 (0x7f)mag1: number- Magic number byte 1 (0x45 - 'E')mag2: number- Magic number byte 2 (0x4c - 'L')mag3: number- Magic number byte 3 (0x46 - 'F')class: ElfClass- File class (32-bit or 64-bit)data: ElfData- Data encoding (little-endian or big-endian)version: ElfVersion- File versionosabi: ElfOsAbi- Operating system/ABI identificationabiversion: number- ABI versionpad: Uint8Array- Padding bytes
Unified program header structure for both 32-bit and 64-bit files:
type: ProgramHeaderTypeflags: ProgramHeaderFlagsoffset: bigintvaddr: bigintpaddr: bigintfilesz: bigintmemsz: bigintalign: bigint
All address and size fields use bigint to support both architectures. The actual size used when reading/writing depends on the ELF class.
Unified section header structure for both 32-bit and 64-bit files:
name: numbertype: SectionHeaderTypeflags: bigintaddr: bigintoffset: bigintsize: bigintlink: numberinfo: numberaddralign: bigintentsize: bigint
All address and size fields use bigint to support both architectures. The actual size used when reading/writing depends on the ELF class.
File class identification:
ELFCLASSNONE = 0- Invalid classELFCLASS32 = 1- 32-bit objectsELFCLASS64 = 2- 64-bit objects
Data encoding:
ELFDATANONE = 0- Invalid data encodingELFDATA2LSB = 1- Little-endianELFDATA2MSB = 2- Big-endian
File version:
EV_NONE = 0- Invalid versionEV_CURRENT = 1- Current version
Operating system/ABI identification:
ELFOSABI_NONE = 0- No extensions or unspecifiedELFOSABI_LINUX = 3- LinuxELFOSABI_FREEBSD = 9- FreeBSD- And many more...
Object file type:
ET_NONE = 0- No file typeET_REL = 1- Relocatable fileET_EXEC = 2- Executable fileET_DYN = 3- Shared object fileET_CORE = 4- Core file
Machine architecture:
EM_386 = 3- Intel 80386EM_X86_64 = 62- AMD x86-64EM_ARM = 40- ARMEM_AARCH64 = 183- ARM 64-bit- And many more...
Program header type:
PT_NULL = 0- Unused entryPT_LOAD = 1- Loadable segmentPT_DYNAMIC = 2- Dynamic linking informationPT_INTERP = 3- Program interpreter- And more...
Program header flags:
PF_X = 0x1- Execute permissionPF_W = 0x2- Write permissionPF_R = 0x4- Read permission
Section header type:
SHT_NULL = 0- Inactive sectionSHT_PROGBITS = 1- Program dataSHT_SYMTAB = 2- Symbol tableSHT_STRTAB = 3- String table- And many more...
Section header flags:
SHF_WRITE = 0x1- WritableSHF_ALLOC = 0x2- Occupies memory during executionSHF_EXECINSTR = 0x4- Executable- And more...
MIT