Class: PatchELF::Patcher

Inherits:
Object
  • Object
show all
Defined in:
lib/patchelf/patcher.rb

Overview

Class to handle all patching things.

Instance Method Summary collapse

Constructor Details

#initialize(filename, logging: true) ⇒ Patcher

Instantiate a PatchELF::Patcher object.

Parameters:

  • filename (String)

    Filename of input ELF.

  • logging (Boolean) (defaults to: true)

    Whether to use a (stderr-initialized) logger for errors



21
22
23
24
25
26
27
# File 'lib/patchelf/patcher.rb', line 21

def initialize(filename, logging: true)
  @in_file = filename
  @elf = ELFTools::ELFFile.new(File.open(filename))
  @set = {}
  @rpath_sym = :runpath
  @logging = logging
end

Instance Method Details

#add_needed(need) ⇒ void

Note:

This setting will be saved after #save being invoked.

This method returns an undefined value.

Add the needed library.

Parameters:

  • need (String)


71
72
73
74
# File 'lib/patchelf/patcher.rb', line 71

def add_needed(need)
  @set[:needed] ||= needed_
  @set[:needed] << need
end

#interpreterString?

Returns Get interpreter’s name.

Examples:

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

Returns:

  • (String?)

    Get interpreter's name.



34
35
36
# File 'lib/patchelf/patcher.rb', line 34

def interpreter
  @set[:interpreter] || interpreter_
end

#interpreter=(interp) ⇒ Object

Note:

This setting will be saved after #save being invoked.

Set interpreter’s name.

If the input ELF has no existent interpreter, this method will show a warning and has no effect.

Parameters:

  • interp (String)


44
45
46
47
48
# File 'lib/patchelf/patcher.rb', line 44

def interpreter=(interp)
  return if interpreter_.nil? # will also show warning if there's no interp segment.

  @set[:interpreter] = interp
end

#neededArray<String>

Get needed libraries.

Examples:

patcher = PatchELF::Patcher.new('/bin/ls')
patcher.needed
#=> ["libselinux.so.1", "libc.so.6"]

Returns:

  • (Array<String>)


56
57
58
# File 'lib/patchelf/patcher.rb', line 56

def needed
  @set[:needed] || needed_
end

#needed=(needs) ⇒ Object

Note:

This setting will be saved after #save being invoked.

Set needed libraries.

Parameters:

  • needs (Array<String>)


63
64
65
# File 'lib/patchelf/patcher.rb', line 63

def needed=(needs)
  @set[:needed] = needs
end

#remove_needed(need) ⇒ void

Note:

This setting will be saved after #save being invoked.

This method returns an undefined value.

Remove the needed library.

Parameters:

  • need (String)


80
81
82
83
# File 'lib/patchelf/patcher.rb', line 80

def remove_needed(need)
  @set[:needed] ||= needed_
  @set[:needed].delete(need)
end

#replace_needed(src, tar) ⇒ void

Note:

This setting will be saved after #save being invoked.

This method returns an undefined value.

Replace needed library src with tar.

Parameters:

  • src (String)

    Library to be replaced.

  • tar (String)

    Library replace with.



93
94
95
96
# File 'lib/patchelf/patcher.rb', line 93

def replace_needed(src, tar)
  @set[:needed] ||= needed_
  @set[:needed].map! { |v| v == src ? tar : v }
end

#runpathString?

Get runpath.

Returns:

  • (String?)


126
127
128
# File 'lib/patchelf/patcher.rb', line 126

def runpath
  @set[@rpath_sym] || runpath_
end

#runpath=(runpath) ⇒ Object

Note:

This setting will be saved after #save being invoked.

Set runpath.

If DT_RUNPATH is not presented in the input ELF, a new DT_RUNPATH attribute will be inserted into the DYNAMIC segment.

Parameters:

  • runpath (String)


136
137
138
# File 'lib/patchelf/patcher.rb', line 136

def runpath=(runpath)
  @set[@rpath_sym] = runpath
end

#save(out_file = nil) ⇒ void

This method returns an undefined value.

Save the patched ELF as out_file.

Parameters:

  • out_file (String?) (defaults to: nil)

    If out_file is nil, the original input file will be modified.



151
152
153
154
155
156
157
158
159
# File 'lib/patchelf/patcher.rb', line 151

def save(out_file = nil)
  # If nothing is modified, return directly.
  return if out_file.nil? && !dirty?

  out_file ||= @in_file
  saver = PatchELF::Saver.new(@in_file, out_file, @set)

  saver.save!
end

#sonameString?

Get the soname of a shared library.

Examples:

patcher = PatchELF::Patcher.new('/bin/ls')
patcher.soname
# [WARN] Entry DT_SONAME not found, not a shared library?
#=> nil
PatchELF::Patcher.new('/lib/x86_64-linux-gnu/libc.so.6').soname
#=> "libc.so.6"

Returns:

  • (String?)

    The name.



108
109
110
# File 'lib/patchelf/patcher.rb', line 108

def soname
  @set[:soname] || soname_
end

#soname=(name) ⇒ Object

Note:

This setting will be saved after #save being invoked.

Set soname.

If the input ELF is not a shared library with a soname, this method will show a warning and has no effect.

Parameters:

  • name (String)


118
119
120
121
122
# File 'lib/patchelf/patcher.rb', line 118

def soname=(name)
  return if soname_.nil?

  @set[:soname] = name
end

#use_rpath!self

Set all operations related to DT_RUNPATH to use DT_RPATH.

Returns:

  • (self)


142
143
144
145
# File 'lib/patchelf/patcher.rb', line 142

def use_rpath!
  @rpath_sym = :rpath
  self
end