项目作者: adelphes

项目描述 :
ELF library for NodeJS
高级语言: JavaScript
项目地址: git://github.com/adelphes/elf-tools.git
创建时间: 2018-09-07T22:07:01Z
项目社区:https://github.com/adelphes/elf-tools

开源协议:

下载


elf-tools

A NodeJS library for building and parsing ELF (Executable and Linker Format) binaries.

Important note: This library currently fails to build valid ELF binaries containing multiple section types due to kernel changes in the validation of ELF binaries. In particular, overlapping sections with different access rights are no longer permitted. See messages around https://lkml.org/lkml/2018/1/7/8

Building an ELF image

There are two ways to output an ELF image:

build(opts)

Use elf_tools.build(opts) to create a buffer containing ELF bytes

  1. const fs = require('fs');
  2. const elf_tools = require('elf-tools');
  3. // create some raw "Hello world!" code for the ELF executable
  4. // note that these instruction bytes are for the Linux OS on Intel/AMD x64 platform
  5. const code = Buffer.from(
  6. '488d3523000000' // lea rsi,[rip+0x23]
  7. +'48c7c20d000000' // mov rdx,0xd
  8. +'48c7c701000000' // mov rdi,0x1
  9. +'48c7c001000000' // mov rax,0x1
  10. +'0f05' // syscall
  11. +'4831ff' // xor rdi,rdi
  12. +'48c7c03c000000' // mov rax,0x3c
  13. +'0f05' // syscall
  14. +'48656c6c6f20776f726c64210a' // "Hello world!\n"
  15. , 'hex');
  16. // build the ELF executable with the code
  17. const image = elf_tools.build({
  18. code,
  19. });
  20. // save the ELF image as a binary executable file
  21. fs.writeFileSync('./a.out', image, { mode: 0o755 });

createBuildStream(opts)

Use elf_tools.createBuildStream(opts) and pipe the result to another Writable stream

  1. const fs = require('fs');
  2. const elf_tools = require('elf-tools');
  3. // create some raw "Hello world!" code for the ELF executable
  4. // note that these instruction bytes are for the Linux OS on Intel/AMD x64 platform
  5. const code = Buffer.from(
  6. '488d3523000000' // lea rsi,[rip+0x23]
  7. +'48c7c20d000000' // mov rdx,0xd
  8. +'48c7c701000000' // mov rdi,0x1
  9. +'48c7c001000000' // mov rax,0x1
  10. +'0f05' // syscall
  11. +'4831ff' // xor rdi,rdi
  12. +'48c7c03c000000' // mov rax,0x3c
  13. +'0f05' // syscall
  14. +'48656c6c6f20776f726c64210a' // "Hello world!\n"
  15. , 'hex');
  16. // create a ELF stream to output the ELF image bytes
  17. const elf_stream = elf_tools.createBuildStream({
  18. code,
  19. });
  20. // create a writable file stream
  21. const file_stream = fs.createWriteStream('./a.out', { mode: 0o755 });
  22. // pipe the ELF bytes to the file
  23. elf_stream.pipe(file_stream);

Once the file is saved, run it from a terminal:

  1. $ ./a.out
  2. Hello world!

Parsing ELF files

To parse an ELF file:

  1. const fs = require('fs');
  2. const elf_tools = require('elf-tools');
  3. // read the file into a buffer
  4. const elf_bytes = fs.readFileSync('./a.out');
  5. // parse the data
  6. const elf = elf_tools.parse(elf_bytes);
  7. // elf is an object containing the parsed ELF-header, program headers (if any) and sections

Documentation

build(opts)

Build an ELF image

  • opts: Object containing code and data to place inside the ELF image

    • code: Buffer. Raw executable code bytes. The ELF builder places this data in a .text section. All calls to build() must include a code buffer. The caller must ensure the code bytes represent valid instructions for the target machine. Important: the code must be position-independant with no relocations.
    • rodata: Buffer (optional). Raw read-only data bytes. The ELF builder places any read-only data in the .text section immediately following the code buffer. If this data needs aligning to a particular byte boundary, the code buffer should be padded accordingly.
    • rwdata: Buffer (optional). Raw read/write data bytes. The ELF builder places any writable data in a .data section following the code and read-only data
    • bss_length: integer (optional). Length of uninitialised (writable) data bytes. The ELF builder locates this data after the rwdata buffer. Although the data is “uninitialized” (because it takes up no space in the ELF image), when the image is run, this section is always zero-filled.
    • base_address: integer (optional). Memory address for loading the elf image (default: 0x400000)
    • entry_offset: integer (optional). Byte offset into the code buffer for the first instruction (default: 0)
    • elf_header: Object (optional). Custom ELF header values. See the notes below for the list of fields supported in this object.
  • returns Buffer containing the complete ELF image

Customising the ELF header

By default, the constructed ELF header contains values based upon your current executing platform. You can override some of these values by passing an elf_header object to build(). The customisable values include:

  • elfsig: string ELF signature
  • class: string '32' or '64' (note that this value is passed as a string, not an integer)
  • endian: string 'lsb' or 'msb'
  • osabi: string Any of the allowed values in lib/constants.js
  • abiversion: string Any of the allowed values in lib/constants.js
  • type: string Any of the allowed values in lib/constants.js
  • machine: string Any of the allowed values in lib/constants.js
  • version: integer Any of the allowed values in lib/constants.js
  • entry: integer ELF entrypoint. Note: this value cannot be set if either base_address or entry_offset are set.
  • flags: integer

The default values for these fields can be found in lib/elf_header.js. Any customised values passed to build() are not validated - make sure you set correct values or the resulting ELF image is likely to be invalid.

Example

This example uses all 4 fields (code, r/o data, r/w data, bss data) to build an executable which:

  • writes out a prompt (r/o data)
  • then reads user-inputted text into a buffer (r/w data)
  • then reverses the text using scratch space (bss data)
  • finally writes out the reversed text and exits the program
  1. const fs = require('fs');
  2. const elf_tools = require('elf-tools');
  3. const opts = {
  4. // note that these instruction bytes are for the Linux OS on Intel/AMD x64 platform
  5. // you can find the source to this program at https://github.com/adelphes/elf-tools/blob/master/test/programs/reverse/reverse.s
  6. code: Buffer.from(`
  7. 488d3579 00000048 c7c21c00 0000e85c 00000048 8d358600 000048c7 c2000100
  8. 00e83e00 000048ff c84889c2 488d3d6d 01000048 01c78a0e 880f48ff cf48ffc6
  9. 4883e801 75f04889 fe48ffc6 c604160a 48ffc2e8 17000000 4831ff48 c7c03c00
  10. 00000f05 bf010000 004831c0 0f05c348 c7c70100 000048c7 c0010000 000f05c3
  11. `.replace(/\s+/g,''), 'hex'),
  12. // add the prompt as read-only bytes - the extra null bytes pad the section to an 8-byte alignment.
  13. rodata: Buffer.from('Enter some text to reverse: \0\0\0\0', 'ascii'),
  14. // pre-allocate 256 zero bytes in the program to store the user-input
  15. rwdata: Buffer.alloc(256),
  16. // reserve another 256 bytes of memory for us to reverse the text
  17. bss_length: 256,
  18. }
  19. // create a ELF stream to output the ELF image bytes
  20. const elf_stream = elf_tools.createStream(opts);
  21. // create a writable file stream
  22. const file_stream = fs.createWriteStream('./reverse', { mode: 0o755 });
  23. // pipe the ELF bytes to the file
  24. elf_stream.pipe(file_stream);

Once the file is saved, run it

  1. $ ./reverse
  2. Enter some text to reverse: abcdef
  3. fedcba