2022-06-05 19:35:02 +02:00
/ * *
* @ author n1073645 [ n1073645 @ gmail . com ]
* @ copyright Crown Copyright 2022
* @ license Apache - 2.0
* /
import Operation from "../Operation.mjs" ;
import Stream from "../lib/Stream.mjs" ;
import Utils from "../Utils.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
/ * *
* ELF Info operation
* /
class ELFInfo extends Operation {
/ * *
* ELFInfo constructor
* /
constructor ( ) {
super ( ) ;
this . name = "ELF Info" ;
this . module = "Default" ;
this . description = "Implements readelf-like functionality. This operation will extract the ELF Header, Program Headers, Section Headers and Symbol Table for an ELF file." ;
this . infoURL = "https://www.wikipedia.org/wiki/Executable_and_Linkable_Format" ;
this . inputType = "ArrayBuffer" ;
this . outputType = "string" ;
this . args = [ ] ;
}
/ * *
* @ param { ArrayBuffer } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run ( input , args ) {
let phoff = 0 ;
let phEntries = 0 ;
let shoff = 0 ;
let shEntries = 0 ;
let shentSize = 0 ;
let entry = 0 ;
let format = 0 ;
let endianness = "" ;
let shstrtab = 0 ;
let namesOffset = 0 ;
let symtabOffset = 0 ;
let symtabSize = 0 ;
let symtabEntSize = 0 ;
let strtabOffset = 0 ;
const align = 30 ;
/ * *
* This function reads characters until it hits a null terminator .
*
* @ param { stream } stream
* @ param { integer } namesOffset
* @ param { integer } nameOffset
* @ returns { string }
* /
function readString ( stream , namesOffset , nameOffset ) {
const preMove = stream . position ;
stream . moveTo ( namesOffset + nameOffset ) ;
2022-06-09 11:15:47 +02:00
const nameResult = stream . readString ( ) ;
2022-06-05 19:35:02 +02:00
stream . moveTo ( preMove ) ;
return nameResult ;
}
/ * *
* This function parses and extracts relevant information from the ELF Header .
*
* @ param { stream } stream
* @ returns { string }
* /
function elfHeader ( stream ) {
/ * *
* The ELF Header is comprised of the following structures depending on the binary ' s format .
*
* e _ident - The Magic Number 0x7F , 0x45 , 0x4c , 0x46
* - Byte set to 1 or 2 to signify 32 - bit or 64 - bit format , respectively .
* - Byte set to 1 or 2 to signify little of big endianness , respectively .
* - Byte set to 1 for the version of ELF .
* - Byte identifying the target OS ABI .
* - Byte further identifying the OS ABI Version .
* - 7 Padding Bytes .
* e _type - 2 bytes identifying the object file type .
* e _machine - 2 bytes identifying the instruction set architecture .
* e _version - Byte set to 1 for the version of ELF .
*
* 32 - bit :
* e _entry - 4 Bytes specifying the entry point .
* e _phoff - 4 Bytes specifying the offset of the Program Header Table .
* e _shoff - 4 Bytes specifying the offset of the Section Header Table .
*
* 64 - bit :
* e _entry - 8 Bytes specifying the entry point .
* e _phoff - 8 Bytes specifying the offset of the Program Header Table .
* e _shoff - 8 Bytes specifying the offset of the Section Header Table .
*
* e _flags - 4 Bytes specifying processor specific flags .
* e _ehsize - 2 Bytes specifying the size of the ELF Header .
* e _phentsize - 2 Bytes specifying the size of a Program Header Table Entry .
* e _phnum - 2 Bytes specifying the number of entries in the Program Header Table .
* e _shentsize - 2 Bytes specifying the size of a Section Header Table Entry .
* e _shnum - 2 Bytes specifying the number of entries in the Section Header Table .
* e _shstrndx - 2 Bytes specifying the index of the section containing the section names in the Section Header Table .
* /
const ehResult = [ ] ;
const magic = stream . getBytes ( 4 ) ;
if ( magic . join ( "" ) !== [ 0x7f , 0x45 , 0x4c , 0x46 ] . join ( "" ) )
throw new OperationError ( "Invalid ELF" ) ;
ehResult . push ( "Magic:" . padEnd ( align ) + ` ${ Utils . byteArrayToChars ( magic ) } ` ) ;
format = stream . readInt ( 1 ) ;
ehResult . push ( "Format:" . padEnd ( align ) + ` ${ format === 1 ? "32-bit" : "64-bit" } ` ) ;
endianness = stream . readInt ( 1 ) === 1 ? "le" : "be" ;
2022-06-09 11:02:38 +02:00
ehResult . push ( "Endianness:" . padEnd ( align ) + ` ${ endianness === "le" ? "Little" : "Big" } ` ) ;
2022-06-05 19:35:02 +02:00
ehResult . push ( "Version:" . padEnd ( align ) + ` ${ stream . readInt ( 1 ) . toString ( ) } ` ) ;
let ABI = "" ;
switch ( stream . readInt ( 1 ) ) {
case 0x00 :
ABI = "System V" ;
break ;
case 0x01 :
ABI = "HP-UX" ;
break ;
case 0x02 :
ABI = "NetBSD" ;
break ;
case 0x03 :
ABI = "Linux" ;
break ;
case 0x04 :
ABI = "GNU Hurd" ;
break ;
case 0x06 :
ABI = "Solaris" ;
break ;
case 0x07 :
ABI = "AIX" ;
break ;
case 0x08 :
ABI = "IRIX" ;
break ;
case 0x09 :
ABI = "FreeBSD" ;
break ;
case 0x0A :
ABI = "Tru64" ;
break ;
case 0x0B :
ABI = "Novell Modesto" ;
break ;
case 0x0C :
ABI = "OpenBSD" ;
break ;
case 0x0D :
ABI = "OpenVMS" ;
break ;
case 0x0E :
ABI = "NonStop Kernel" ;
break ;
case 0x0F :
ABI = "AROS" ;
break ;
case 0x10 :
ABI = "Fenix OS" ;
break ;
case 0x11 :
ABI = "CloudABI" ;
break ;
case 0x12 :
ABI = "Stratus Technologies OpenVOS" ;
break ;
default :
break ;
}
ehResult . push ( "ABI:" . padEnd ( align ) + ABI ) ;
// Linux Kernel does not use ABI Version.
const abiVersion = stream . readInt ( 1 ) . toString ( ) ;
if ( ABI !== "Linux" )
ehResult . push ( "ABI Version:" . padEnd ( align ) + abiVersion ) ;
stream . moveForwardsBy ( 7 ) ;
let eType = "" ;
switch ( stream . readInt ( 2 , endianness ) ) {
case 0x0000 :
eType = "Unknown" ;
break ;
case 0x0001 :
eType = "Relocatable File" ;
break ;
case 0x0002 :
eType = "Executable File" ;
break ;
case 0x0003 :
eType = "Shared Object" ;
break ;
case 0x0004 :
eType = "Core File" ;
break ;
case 0xFE00 :
eType = "LOOS" ;
break ;
case 0xFEFF :
eType = "HIOS" ;
break ;
case 0xFF00 :
eType = "LOPROC" ;
break ;
case 0xFFFF :
eType = "HIPROC" ;
break ;
default :
break ;
}
ehResult . push ( "Type:" . padEnd ( align ) + eType ) ;
let ISA = "" ;
switch ( stream . readInt ( 2 , endianness ) ) {
case 0x0000 :
ISA = "No specific instruction set" ;
break ;
case 0x0001 :
ISA = "AT&T WE 32100" ;
break ;
case 0x0002 :
ISA = "SPARC" ;
break ;
case 0x0003 :
ISA = "x86" ;
break ;
case 0x0004 :
ISA = "Motorola 68000 (M68k)" ;
break ;
case 0x0005 :
ISA = "Motorola 88000 (M88k)" ;
break ;
case 0x0006 :
ISA = "Intel MCU" ;
break ;
case 0x0007 :
ISA = "Intel 80860" ;
break ;
case 0x0008 :
ISA = "MIPS" ;
break ;
case 0x0009 :
ISA = "IBM System/370" ;
break ;
case 0x000A :
ISA = "MIPS RS3000 Little-endian" ;
break ;
case 0x000B :
case 0x000C :
case 0x000D :
case 0x000E :
case 0x0018 :
case 0x0019 :
case 0x001A :
case 0x001B :
case 0x001C :
case 0x001D :
case 0x001E :
case 0x001F :
case 0x0020 :
case 0x0021 :
case 0x0022 :
case 0x0023 :
ISA = "Reserved for future use" ;
break ;
case 0x000F :
ISA = "Hewlett-Packard PA-RISC" ;
break ;
case 0x0011 :
ISA = "Fujitsu VPP500" ;
break ;
case 0x0012 :
ISA = "Enhanced instruction set SPARC" ;
break ;
case 0x0013 :
ISA = "Intel 80960" ;
break ;
case 0x0014 :
ISA = "PowerPC" ;
break ;
case 0x0015 :
ISA = "PowerPC (64-bit)" ;
break ;
case 0x0016 :
ISA = "S390, including S390" ;
break ;
case 0x0017 :
ISA = "IBM SPU/SPC" ;
break ;
case 0x0024 :
ISA = "NEC V800" ;
break ;
case 0x0025 :
ISA = "Fujitsu FR20" ;
break ;
case 0x0026 :
ISA = "TRW RH-32" ;
break ;
case 0x0027 :
ISA = "Motorola RCE" ;
break ;
case 0x0028 :
ISA = "ARM (up to ARMv7/Aarch32)" ;
break ;
case 0x0029 :
ISA = "Digital Alpha" ;
break ;
case 0x002A :
ISA = "SuperH" ;
break ;
case 0x002B :
ISA = "SPARC Version 9" ;
break ;
case 0x002C :
ISA = "Siemens TriCore embedded processor" ;
break ;
case 0x002D :
ISA = "Argonaut RISC Core" ;
break ;
case 0x002E :
ISA = "Hitachi H8/300" ;
break ;
case 0x002F :
ISA = "Hitachi H8/300H" ;
break ;
case 0x0030 :
ISA = "Hitachi H8S" ;
break ;
case 0x0031 :
ISA = "Hitachi H8/500" ;
break ;
case 0x0032 :
ISA = "IA-64" ;
break ;
case 0x0033 :
ISA = "Standford MIPS-X" ;
break ;
case 0x0034 :
ISA = "Motorola ColdFire" ;
break ;
case 0x0035 :
ISA = "Motorola M68HC12" ;
break ;
case 0x0036 :
ISA = "Fujitsu MMA Multimedia Accelerator" ;
break ;
case 0x0037 :
ISA = "Siemens PCP" ;
break ;
case 0x0038 :
ISA = "Sony nCPU embedded RISC processor" ;
break ;
case 0x0039 :
ISA = "Denso NDR1 microprocessor" ;
break ;
case 0x003A :
ISA = "Motorola Star*Core processor" ;
break ;
case 0x003B :
ISA = "Toyota ME16 processor" ;
break ;
case 0x003C :
ISA = "STMicroelectronics ST100 processor" ;
break ;
case 0x003D :
ISA = "Advanced Logic Corp. TinyJ embedded processor family" ;
break ;
case 0x003E :
ISA = "AMD x86-64" ;
break ;
case 0x003F :
ISA = "Sony DSP Processor" ;
break ;
case 0x0040 :
ISA = "Digital Equipment Corp. PDP-10" ;
break ;
case 0x0041 :
ISA = "Digital Equipment Corp. PDP-11" ;
break ;
case 0x0042 :
ISA = "Siemens FX66 microcontroller" ;
break ;
case 0x0043 :
ISA = "STMicroelectronics ST9+ 8/16 bit microcontroller" ;
break ;
case 0x0044 :
ISA = "STMicroelectronics ST7 8-bit microcontroller" ;
break ;
case 0x0045 :
ISA = "Motorola MC68HC16 Microcontroller" ;
break ;
case 0x0046 :
ISA = "Motorola MC68HC11 Microcontroller" ;
break ;
case 0x0047 :
ISA = "Motorola MC68HC08 Microcontroller" ;
break ;
case 0x0048 :
ISA = "Motorola MC68HC05 Microcontroller" ;
break ;
case 0x0049 :
ISA = "Silicon Graphics SVx" ;
break ;
case 0x004A :
ISA = "STMicroelectronics ST19 8-bit microcontroller" ;
break ;
case 0x004B :
ISA = "Digital VAX" ;
break ;
case 0x004C :
ISA = "Axis Communications 32-bit embedded processor" ;
break ;
case 0x004D :
ISA = "Infineon Technologies 32-bit embedded processor" ;
break ;
case 0x004E :
ISA = "Element 14 64-bit DSP Processor" ;
break ;
case 0x004F :
ISA = "LSI Logic 16-bit DSP Processor" ;
break ;
case 0x0050 :
ISA = "Donald Knuth's educational 64-bit processor" ;
break ;
case 0x0051 :
ISA = "Harvard University machine-independent object files" ;
break ;
case 0x0052 :
ISA = "SiTera Prism" ;
break ;
case 0x0053 :
ISA = "Atmel AVR 8-bit microcontroller" ;
break ;
case 0x0054 :
ISA = "Fujitsu FR30" ;
break ;
case 0x0055 :
ISA = "Mitsubishi D10V" ;
break ;
case 0x0056 :
ISA = "Mitsubishi D30V" ;
break ;
case 0x0057 :
ISA = "NEC v850" ;
break ;
case 0x0058 :
ISA = "Mitsubishi M32R" ;
break ;
case 0x0059 :
ISA = "Matsushita MN10300" ;
break ;
case 0x005A :
ISA = "Matsushita MN10200" ;
break ;
case 0x005B :
ISA = "picoJava" ;
break ;
case 0x005C :
ISA = "OpenRISC 32-bit embedded processor" ;
break ;
case 0x005D :
ISA = "ARC Cores Tangent-A5" ;
break ;
case 0x005E :
ISA = "Tensilica Xtensa Architecture" ;
break ;
case 0x005F :
ISA = "Alphamosaic VideoCore processor" ;
break ;
case 0x0060 :
ISA = "Thompson Multimedia General Purpose Processor" ;
break ;
case 0x0061 :
ISA = "National Semiconductor 32000 series" ;
break ;
case 0x0062 :
ISA = "Tenor Network TPC processor" ;
break ;
case 0x0063 :
ISA = "Trebia SNP 1000 processor" ;
break ;
case 0x0064 :
ISA = "STMicroelectronics (www.st.com) ST200 microcontroller" ;
break ;
case 0x008C :
ISA = "TMS320C6000 Family" ;
break ;
case 0x00AF :
ISA = "MCST Elbrus e2k" ;
break ;
case 0x00B7 :
ISA = "ARM 64-bits (ARMv8/Aarch64)" ;
break ;
case 0x00F3 :
ISA = "RISC-V" ;
break ;
case 0x00F7 :
ISA = "Berkeley Packet Filter" ;
break ;
case 0x0101 :
ISA = "WDC 65C816" ;
break ;
default :
ISA = "Unimplemented" ;
break ;
}
ehResult . push ( "Instruction Set Architecture:" . padEnd ( align ) + ISA ) ;
ehResult . push ( "ELF Version:" . padEnd ( align ) + ` ${ stream . readInt ( 4 , endianness ) } ` ) ;
const readSize = format === 1 ? 4 : 8 ;
entry = stream . readInt ( readSize , endianness ) ;
phoff = stream . readInt ( readSize , endianness ) ;
shoff = stream . readInt ( readSize , endianness ) ;
ehResult . push ( "Entry Point:" . padEnd ( align ) + ` 0x ${ Utils . hex ( entry ) } ` ) ;
ehResult . push ( "Entry PHOFF:" . padEnd ( align ) + ` 0x ${ Utils . hex ( phoff ) } ` ) ;
ehResult . push ( "Entry SHOFF:" . padEnd ( align ) + ` 0x ${ Utils . hex ( shoff ) } ` ) ;
const flags = stream . readInt ( 4 , endianness ) ;
ehResult . push ( "Flags:" . padEnd ( align ) + ` ${ Utils . bin ( flags ) } ` ) ;
ehResult . push ( "ELF Header Size:" . padEnd ( align ) + ` ${ stream . readInt ( 2 , endianness ) } bytes ` ) ;
ehResult . push ( "Program Header Size:" . padEnd ( align ) + ` ${ stream . readInt ( 2 , endianness ) } bytes ` ) ;
phEntries = stream . readInt ( 2 , endianness ) ;
ehResult . push ( "Program Header Entries:" . padEnd ( align ) + phEntries ) ;
shentSize = stream . readInt ( 2 , endianness ) ;
ehResult . push ( "Section Header Size:" . padEnd ( align ) + shentSize + " bytes" ) ;
shEntries = stream . readInt ( 2 , endianness ) ;
ehResult . push ( "Section Header Entries:" . padEnd ( align ) + shEntries ) ;
shstrtab = stream . readInt ( 2 , endianness ) ;
ehResult . push ( "Section Header Names:" . padEnd ( align ) + shstrtab ) ;
return ehResult . join ( "\n" ) ;
}
/ * *
* This function parses and extracts relevant information from a Program Header .
*
* @ param { stream } stream
* @ returns { string }
* /
function programHeader ( stream ) {
/ * *
* A Program Header is comprised of the following structures depending on the binary ' s format .
*
* p _type - 4 Bytes identifying the type of the segment .
*
* 32 - bit :
* p _offset - 4 Bytes specifying the offset of the segment .
* p _vaddr - 4 Bytes specifying the virtual address of the segment in memory .
* p _paddr - 4 Bytes specifying the physical address of the segment in memory .
* p _filesz - 4 Bytes specifying the size in bytes of the segment in the file image .
* p _memsz - 4 Bytes specifying the size in bytes of the segment in memory .
* p _flags - 4 Bytes identifying the segment dependent flags .
* p _align - 4 Bytes set to 0 or 1 for alignment or no alignment , respectively .
*
* 64 - bit :
* p _flags - 4 Bytes identifying segment dependent flags .
* p _offset - 8 Bytes specifying the offset of the segment .
* p _vaddr - 8 Bytes specifying the virtual address of the segment in memory .
* p _paddr - 8 Bytes specifying the physical address of the segment in memory .
* p _filesz - 8 Bytes specifying the size in bytes of the segment in the file image .
* p _memsz - 8 Bytes specifying the size in bytes of the segment in memory .
* p _align - 8 Bytes set to 0 or 1 for alignment or no alignment , respectively .
* /
/ * *
* This function decodes the flags bitmask for the Program Header .
*
* @ param { integer } flags
* @ returns { string }
* /
function readFlags ( flags ) {
const result = [ ] ;
if ( flags & 0x1 )
result . push ( "Execute" ) ;
if ( flags & 0x2 )
result . push ( "Write" ) ;
if ( flags & 0x4 )
result . push ( "Read" ) ;
if ( flags & 0xf0000000 )
result . push ( "Unspecified" ) ;
return result . join ( "," ) ;
}
const phResult = [ ] ;
let pType = "" ;
const programHeaderType = stream . readInt ( 4 , endianness ) ;
switch ( true ) {
case ( programHeaderType === 0x00000000 ) :
pType = "Unused" ;
break ;
case ( programHeaderType === 0x00000001 ) :
pType = "Loadable Segment" ;
break ;
case ( programHeaderType === 0x00000002 ) :
pType = "Dynamic linking information" ;
break ;
case ( programHeaderType === 0x00000003 ) :
pType = "Interpreter Information" ;
break ;
case ( programHeaderType === 0x00000004 ) :
pType = "Auxiliary Information" ;
break ;
case ( programHeaderType === 0x00000005 ) :
pType = "Reserved" ;
break ;
case ( programHeaderType === 0x00000006 ) :
pType = "Program Header Table" ;
break ;
case ( programHeaderType === 0x00000007 ) :
pType = "Thread-Local Storage Template" ;
break ;
case ( programHeaderType >= 0x60000000 && programHeaderType <= 0x6FFFFFFF ) :
pType = "Reserved Inclusive Range. OS Specific" ;
break ;
case ( programHeaderType >= 0x70000000 && programHeaderType <= 0x7FFFFFFF ) :
pType = "Reserved Inclusive Range. Processor Specific" ;
break ;
default :
break ;
}
phResult . push ( "Program Header Type:" . padEnd ( align ) + pType ) ;
if ( format === 2 )
phResult . push ( "Flags:" . padEnd ( align ) + readFlags ( stream . readInt ( 4 , endianness ) ) ) ;
const readSize = format === 1 ? 4 : 8 ;
phResult . push ( "Offset Of Segment:" . padEnd ( align ) + ` ${ stream . readInt ( readSize , endianness ) } ` ) ;
phResult . push ( "Virtual Address of Segment:" . padEnd ( align ) + ` ${ stream . readInt ( readSize , endianness ) } ` ) ;
phResult . push ( "Physical Address of Segment:" . padEnd ( align ) + ` ${ stream . readInt ( readSize , endianness ) } ` ) ;
phResult . push ( "Size of Segment:" . padEnd ( align ) + ` ${ stream . readInt ( readSize , endianness ) } bytes ` ) ;
phResult . push ( "Size of Segment in Memory:" . padEnd ( align ) + ` ${ stream . readInt ( readSize , endianness ) } bytes ` ) ;
if ( format === 1 )
phResult . push ( "Flags:" . padEnd ( align ) + readFlags ( stream . readInt ( 4 , endianness ) ) ) ;
stream . moveForwardsBy ( readSize ) ;
return phResult . join ( "\n" ) ;
}
/ * *
* This function parses and extracts relevant information from a Section Header .
*
* @ param { stream } stream
* @ returns { string }
* /
function sectionHeader ( stream ) {
/ * *
* A Section Header is comprised of the following structures depending on the binary ' s format .
*
* sh _name - 4 Bytes identifying the offset into the . shstrtab for the name of this section .
* sh _type - 4 Bytes identifying the type of this header .
*
* 32 - bit :
* sh _flags - 4 Bytes identifying section specific flags .
* sh _addr - 4 Bytes identifying the virtual address of the section in memory .
* sh _offset - 4 Bytes identifying the offset of the section in the file .
* sh _size - 4 Bytes specifying the size in bytes of the section in the file image .
* sh _link - 4 Bytes identifying the index of an associated section .
* sh _info - 4 Bytes specifying extra information about the section .
* sh _addralign - 4 Bytes containing the alignment for the section .
* sh _entsize - 4 Bytes specifying the size , in bytes , of each entry in the section .
*
* 64 - bit :
* sh _flags - 8 Bytes identifying section specific flags .
* sh _addr - 8 Bytes identifying the virtual address of the section in memory .
* sh _offset - 8 Bytes identifying the offset of the section in the file .
* sh _size - 8 Bytes specifying the size in bytes of the section in the file image .
* sh _link - 4 Bytes identifying the index of an associated section .
* sh _info - 4 Bytes specifying extra information about the section .
* sh _addralign - 8 Bytes containing the alignment for the section .
* sh _entsize - 8 Bytes specifying the size , in bytes , of each entry in the section .
* /
const shResult = [ ] ;
const nameOffset = stream . readInt ( 4 , endianness ) ;
let type = "" ;
const shType = stream . readInt ( 4 , endianness ) ;
switch ( true ) {
case ( shType === 0x00000001 ) :
type = "Program Data" ;
break ;
case ( shType === 0x00000002 ) :
type = "Symbol Table" ;
break ;
case ( shType === 0x00000003 ) :
type = "String Table" ;
break ;
case ( shType === 0x00000004 ) :
type = "Relocation Entries with Addens" ;
break ;
case ( shType === 0x00000005 ) :
type = "Symbol Hash Table" ;
break ;
case ( shType === 0x00000006 ) :
type = "Dynamic Linking Information" ;
break ;
case ( shType === 0x00000007 ) :
type = "Notes" ;
break ;
case ( shType === 0x00000008 ) :
type = "Program Space with No Data" ;
break ;
case ( shType === 0x00000009 ) :
type = "Relocation Entries with no Addens" ;
break ;
case ( shType === 0x0000000A ) :
type = "Reserved" ;
break ;
case ( shType === 0x0000000B ) :
type = "Dynamic Linker Symbol Table" ;
break ;
case ( shType === 0x0000000E ) :
type = "Array of Constructors" ;
break ;
case ( shType === 0x0000000F ) :
type = "Array of Destructors" ;
break ;
case ( shType === 0x00000010 ) :
type = "Array of pre-constructors" ;
break ;
case ( shType === 0x00000011 ) :
type = "Section group" ;
break ;
case ( shType === 0x00000012 ) :
type = "Extended section indices" ;
break ;
case ( shType === 0x00000013 ) :
type = "Number of defined types" ;
break ;
case ( shType >= 0x60000000 && shType <= 0x6fffffff ) :
type = "OS-specific" ;
break ;
case ( shType >= 0x70000000 && shType <= 0x7fffffff ) :
type = "Processor-specific" ;
break ;
case ( shType >= 0x80000000 && shType <= 0x8fffffff ) :
type = "Application-specific" ;
break ;
default :
type = "Unused" ;
break ;
}
shResult . push ( "Type:" . padEnd ( align ) + type ) ;
let nameResult = "" ;
if ( type !== "Unused" ) {
nameResult = readString ( stream , namesOffset , nameOffset ) ;
shResult . push ( "Section Name: " . padEnd ( align ) + nameResult ) ;
}
const readSize = ( format === 1 ) ? 4 : 8 ;
const flags = stream . readInt ( readSize , endianness ) ;
const shFlags = [ ] ;
const bitMasks = [
[ 0x00000001 , "Writable" ] ,
[ 0x00000002 , "Alloc" ] ,
[ 0x00000004 , "Executable" ] ,
[ 0x00000010 , "Merge" ] ,
[ 0x00000020 , "Strings" ] ,
[ 0x00000040 , "SHT Info Link" ] ,
[ 0x00000080 , "Link Order" ] ,
[ 0x00000100 , "OS Specific Handling" ] ,
[ 0x00000200 , "Group" ] ,
[ 0x00000400 , "Thread Local Data" ] ,
[ 0x0FF00000 , "OS-Specific" ] ,
[ 0xF0000000 , "Processor Specific" ] ,
[ 0x04000000 , "Special Ordering (Solaris)" ] ,
[ 0x08000000 , "Excluded (Solaris)" ]
] ;
bitMasks . forEach ( elem => {
if ( flags & elem [ 0 ] )
shFlags . push ( elem [ 1 ] ) ;
} ) ;
shResult . push ( "Flags:" . padEnd ( align ) + shFlags ) ;
const vaddr = stream . readInt ( readSize , endianness ) ;
shResult . push ( "Section Vaddr in memory:" . padEnd ( align ) + vaddr ) ;
const shoffset = stream . readInt ( readSize , endianness ) ;
shResult . push ( "Offset of the section:" . padEnd ( align ) + shoffset ) ;
const secSize = stream . readInt ( readSize , endianness ) ;
shResult . push ( "Section Size:" . padEnd ( align ) + secSize ) ;
const associatedSection = stream . readInt ( 4 , endianness ) ;
shResult . push ( "Associated Section:" . padEnd ( align ) + associatedSection ) ;
const extraInfo = stream . readInt ( 4 , endianness ) ;
shResult . push ( "Section Extra Information:" . padEnd ( align ) + extraInfo ) ;
// Jump over alignment field.
stream . moveForwardsBy ( readSize ) ;
const entSize = stream . readInt ( readSize , endianness ) ;
switch ( nameResult ) {
case ".strtab" :
strtabOffset = shoffset ;
break ;
case ".symtab" :
symtabOffset = shoffset ;
symtabSize = secSize ;
symtabEntSize = entSize ;
break ;
default :
break ;
}
return shResult . join ( "\n" ) ;
}
/ * *
* This function returns the offset of the Section Header Names Section .
*
* @ param { stream } stream
* /
function getNamesOffset ( stream ) {
const preMove = stream . position ;
stream . moveTo ( shoff + ( shentSize * shstrtab ) ) ;
if ( format === 1 ) {
stream . moveForwardsBy ( 0x10 ) ;
namesOffset = stream . readInt ( 4 , endianness ) ;
} else {
stream . moveForwardsBy ( 0x18 ) ;
namesOffset = stream . readInt ( 8 , endianness ) ;
}
stream . position = preMove ;
}
/ * *
* This function returns a symbol ' s name from the string table .
*
* @ param { stream } stream
* @ returns { string }
* /
function getSymbols ( stream ) {
/ * *
* The Symbol Table is comprised of Symbol Table Entries whose structure depends on the binary ' s format .
*
* 32 - bit :
* st _name - 4 Bytes specifying an index in the files symbol string table .
* st _value - 4 Bytes identifying the value associated with the symbol .
* st _size - 4 Bytes specifying the size associated with the symbol ( this is not the size of the symbol ) .
* st _info - A byte specifying the type and binding of the symbol .
* st _other - A byte specifying the symbol ' s visibility .
* st _shndx - 2 Bytes identifying the section that this symbol is related to .
*
* 64 - bit :
* st _name - 4 Bytes specifying an index in the files symbol string table .
* st _info - A byte specifying the type and binding of the symbol .
* st _other - A byte specifying the symbol ' s visibility .
* st _shndx - 2 Bytes identifying the section that this symbol is related to .
* st _value - 8 Bytes identifying the value associated with the symbol .
* st _size - 8 Bytes specifying the size associated with the symbol ( this is not the size of the symbol ) .
* /
const nameOffset = stream . readInt ( 4 , endianness ) ;
stream . moveForwardsBy ( format === 2 ? 20 : 12 ) ;
return readString ( stream , strtabOffset , nameOffset ) ;
}
input = new Uint8Array ( input ) ;
const stream = new Stream ( input ) ;
const result = [ "=" . repeat ( align ) + " ELF Header " + "=" . repeat ( align ) ] ;
result . push ( elfHeader ( stream ) + "\n" ) ;
getNamesOffset ( stream ) ;
result . push ( "=" . repeat ( align ) + " Program Header " + "=" . repeat ( align ) ) ;
stream . moveTo ( phoff ) ;
for ( let i = 0 ; i < phEntries ; i ++ )
result . push ( programHeader ( stream ) + "\n" ) ;
result . push ( "=" . repeat ( align ) + " Section Header " + "=" . repeat ( align ) ) ;
stream . moveTo ( shoff ) ;
for ( let i = 0 ; i < shEntries ; i ++ )
result . push ( sectionHeader ( stream ) + "\n" ) ;
result . push ( "=" . repeat ( align ) + " Symbol Table " + "=" . repeat ( align ) ) ;
stream . moveTo ( symtabOffset ) ;
let elem = "" ;
for ( let i = 0 ; i < ( symtabSize / symtabEntSize ) ; i ++ )
if ( ( elem = getSymbols ( stream ) ) !== "" )
result . push ( "Symbol Name:" . padEnd ( align ) + elem ) ;
return result . join ( "\n" ) ;
}
}
export default ELFInfo ;