In the past, we learned about the setup of Ruby debugging environment and basic Ruby syntax. Today, we will use Ruby’s advanced library to modify iOS dynamic library files.

ruby-macho

In Ruby, ruby-macho is used to modify Mach O files. The rules can be found on Github, the repository address is Ruby-Macho.

Modify the Load Command of the dynamic library

Construction project Engineering

We create a new folder and create a Gemfile file to which we introduce the necessary libraries for Ruby debugging and ruby-macho

Gemfile:

source 'https://rubygems.org'

gem 'ruby-debug-ide'
gem 'debase'
gem 'rexml'
gem 'ruby-macho'
gem 'solargraph'
Copy the code

Next, place the libAFNetworking. Dylib file in the bin directory in the root folder, as shown in the following figure:

View dependency information for dynamic libraries

require 'macho' // 1 macho_path_dylib = './bin/libAFNetworking.dylib' macho_path_copy_dylib = './bin/ libafnetworking_copy.dylib 'fileutils. cp macho_path_dylib, macho_path_copy_dylib // 2 # The dynamic library relies on the dynamic library file_dylibs = MachO: : view dylibs (macho_path_dylib) / / 3 file_dylibs. Each do | dylib | puts dylib end output:  /System/Library/Frameworks/Foundation.framework/Foundation /usr/lib/libobjc.A.dylib /usr/lib/libSystem.B.dylib /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics /System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices /System/Library/Frameworks/Security.framework/Security /System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration /System/Library/Frameworks/UIKit.framework/UIKit /System/Library/Frameworks/WebKit.framework/WebKitCopy the code
  • 1, the introduction ofmachoRuby library.
  • Make a copy of the dynamic library.
  • 3, check theThe dynamic libraryorExecutable fileYou can view other library files that the dynamic library depends on.

Modify rpath

For the meaning of RPATH in dynamic libraries, see this article dynamic Library Principles.

1. First, let’s check the RPATH value in the dynamic database:

Copy = MachO:: machofile. new(macho_path_copy_dylib) Origin = MachO:: machofile. new(macho_path_dylib) puts "views rpath: - copy - # {copy. Rpaths} -- -- -- -- -- origin -- -- -- -- -- - : # {origin. Rpaths} "output: view rpath: -- copy ---- ["@executable_path/Frameworks", "@loader_path/Frameworks"] ----- origin ------: ["@executable_path/Frameworks", "@loader_path/Frameworks"]Copy the code

2. Change the rpath value

# change rpath MachO:: tools. change_rpath(macho_path_copy_dylib, '@loader_path/Frameworks', '@loader_path/Frameworks/LY') copy = MachO::MachOFile.new(macho_path_copy_dylib) origin = MachO::MachOFile.new(macho_path_dylib) puts "modify rpath >>>>>>: #{copy.rpaths} ----- origin ------: #{origine. rpaths}" modify rpath >>>>>>: ["@executable_path/Frameworks", "@loader_path/Frameworks/LY"] ----- origin ------: ["@executable_path/Frameworks", "@loader_path/Frameworks"]Copy the code

From here we can see that we have successfully changed @loader_path/Frameworks/LY from libafNetworking_copy. dylib to @loader_path/Frameworks/LY.

3. Add the rpath value

MachO::Tools.add_rpath(macho_path_copy_dylib, '@loader_path/Frameworks/LY1/LY2') copy = MachO::MachOFile.new(macho_path_copy_dylib) origin = MachO::MachOFile.new(macho_path_dylib) puts "add rpath >>>>>: #{copy.rpaths} ----- origin ------: #{origine.rpaths}" add rpath >>>>>: ["@executable_path/Frameworks", "@loader_path/Frameworks/LY", "@loader_path/Frameworks/LY1/LY2"] ----- origin ------: ["@executable_path/Frameworks", "@loader_path/Frameworks"]Copy the code

We have now successfully added a new RPATH to the replica dynamic library.

4. Delete the Rpath

# delete rpath MachO:: tools. delete_rpath(macho_path_copy_dylib, '@loader_path/Frameworks/LY1/LY2') copy = MachO::MachOFile.new(macho_path_copy_dylib) puts "delete rpath >>>>: # {copy. Rpaths} -- -- -- -- -- -- origin -- -- -- -- -- : # {origin. Rpaths} "output: delete rpath > > > > : ["@executable_path/Frameworks", "@loader_path/Frameworks/LY"] ------origin-----: ["@executable_path/Frameworks", "@loader_path/Frameworks"]Copy the code

This is a simple implementation of Ruby-Macho in modifying Mach O files. The complete code is as follows:

require 'macho' #ruby-macho macho_path_dylib = './bin/libAFNetworking.dylib' macho_path_copy_dylib = './bin/libAFNetworking_copy.dylib' # copy macho_path_dylib => macho_path_copy_dylib FileUtils.cp macho_path_dylib, Macho_path_copy_dylib /exec The dynamic library relies on the dynamic library file_dylibs = MachO: : view dylibs (macho_path_dylib) file_dylibs. Each do | dylib | puts dylib end # check rpath Copy = MachO:: machofile. new(macho_path_copy_dylib) Origin = MachO:: machofile. new(macho_path_dylib) puts "views rpath: -- copy ---- #{copy.rpaths} ----- origin ------: #{origin. Rpaths}" #{rootpath :: tools. change_rpath(macho_path_copy_dylib, '@loader_path/Frameworks', '@loader_path/Frameworks/LY') copy = MachO::MachOFile.new(macho_path_copy_dylib) origin = MachO::MachOFile.new(macho_path_dylib) puts "modify rpath >>>>>>: #{copy.rpaths} ----- origin ------: #{origine.rpaths}" # add rpath MachO:: tools. add_rpath(macho_path_copy_dylib, '@loader_path/Frameworks/LY1/LY2') copy = MachO::MachOFile.new(macho_path_copy_dylib) origin = MachO::MachOFile.new(macho_path_dylib) puts "add rpath >>>>>: #{copy.rpaths} ----- origin ------: #{origine.rpaths}" # delete rpath MachO:: tools. delete_rpath(macho_path_copy_dylib, '@loader_path/Frameworks/LY1/LY2') copy = MachO::MachOFile.new(macho_path_copy_dylib) puts "delete rpath >>>>: #{copy.rpaths} ------origin-----: #{origin.rpaths}"Copy the code