mirror of
https://github.com/gchq/CyberChef.git
synced 2024-11-16 08:58:30 +01:00
913 lines
36 KiB
JavaScript
913 lines
36 KiB
JavaScript
/**
|
|
* @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);
|
|
|
|
const nameResult = stream.readString();
|
|
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";
|
|
ehResult.push("Endianness:".padEnd(align) + `${endianness === "le" ? "Little" : "Big"}`);
|
|
|
|
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;
|