Project

patchelf

0.03
The project is in a healthy, maintained state
A simple utility for modifying existing ELF executables and libraries.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
 Project Readme

Build Status Dependabot Status Code Climate Issue Count Test Coverage Inline docs MIT License

patchelf.rb

Implements features of NixOS/patchelf in pure Ruby.

Installation

Available on RubyGems.org!

$ gem install patchelf

Usage

$ patchelf.rb
# Usage: patchelf.rb <commands> FILENAME [OUTPUT_FILE]
#         --print-interpreter, --pi    Show interpreter's name.
#         --print-needed, --pn         Show needed libraries specified in DT_NEEDED.
#         --print-runpath, --pr        Show the path specified in DT_RUNPATH.
#         --print-soname, --ps         Show soname specified in DT_SONAME.
#         --set-interpreter, --interp INTERP
#                                      Set interpreter's name.
#         --set-needed, --needed LIB1,LIB2,LIB3
#                                      Set needed libraries, this will remove all existent needed libraries.
#         --add-needed LIB             Append a new needed library.
#         --remove-needed LIB          Remove a needed library.
#         --replace-needed LIB1,LIB2   Replace needed library LIB1 as LIB2.
#         --set-runpath, --runpath PATH
#                                      Set the path of runpath.
#         --force-rpath                According to the ld.so docs, DT_RPATH is obsolete,
#                                      patchelf.rb will always try to get/set DT_RUNPATH first.
#                                      Use this option to force every operations related to runpath (e.g. --runpath)
#                                      to consider 'DT_RPATH' instead of 'DT_RUNPATH'.
#         --set-soname, --so SONAME    Set name of a shared library.
#         --version                    Show current gem's version.

Display information

$ patchelf.rb --print-interpreter --print-needed /bin/ls
# interpreter: /lib64/ld-linux-x86-64.so.2
# needed: libselinux.so.1 libc.so.6

Change the dynamic loader (interpreter)

# $ patchelf.rb --interp NEW_INTERP input.elf output.elf
$ patchelf.rb --interp /lib/AAAA.so /bin/ls ls.patch

$ file ls.patch
# ls.patch: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/AAAA.so, for GNU/Linux 3.2.0, BuildID[sha1]=9567f9a28e66f4d7ec4baf31cfbf68d0410f0ae6, stripped

Modify dependency libraries

Add

$ patchelf.rb --add-needed libnew.so /bin/ls ls.patch

Remove

$ patchelf.rb --remove-needed libc.so.6 /bin/ls ls.patch

Replace

$ patchelf.rb --replace-needed libc.so.6,libcnew.so.6 /bin/ls ls.patch

$ readelf -d ls.patch | grep NEEDED
#  0x0000000000000001 (NEEDED)             Shared library: [libselinux.so.1]
#  0x0000000000000001 (NEEDED)             Shared library: [libcnew.so.6]

Set directly

$ patchelf.rb --needed a.so,b.so,c.so /bin/ls ls.patch

$ readelf -d ls.patch | grep NEEDED
#  0x0000000000000001 (NEEDED)             Shared library: [a.so]
#  0x0000000000000001 (NEEDED)             Shared library: [b.so]
#  0x0000000000000001 (NEEDED)             Shared library: [c.so]

Set RUNPATH of an executable

$ patchelf.rb --runpath . /bin/ls ls.patch

$ readelf -d ls.patch | grep RUNPATH
#  0x000000000000001d (RUNPATH)            Library runpath: [.]

Change SONAME of a shared library

$ patchelf.rb --so libc.so.217 /lib/x86_64-linux-gnu/libc.so.6 libc.patch

$ readelf -d libc.patch | grep SONAME
#  0x000000000000000e (SONAME)             Library soname: [libc.so.217]

As Ruby library

require 'patchelf'

patcher = PatchELF::Patcher.new('/bin/ls')
patcher.interpreter
#=> "/lib64/ld-linux-x86-64.so.2"

patcher.interpreter = '/lib/AAAA.so.2'
patcher.interpreter
#=> "/lib/AAAA.so.2"

patcher.save('ls.patch')

# $ file ls.patch
# ls.patch: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/AAAA.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=9567f9a28e66f4d7ec4baf31cfbf68d0410f0ae6, stripped

Environment

patchelf.rb is implemented in pure Ruby, so it should work in all environments include Linux, macOS, and Windows!