在前面我们了解了Ruby调试环境的搭建和Ruby基本语法,今天我们通过Ruby中的高级库来修改iOS的动态库文件。
ruby-macho
在Ruby中,ruby-macho是用来修改Mach O文件的。我们可以通过Github来了解其使用规则,仓库地址为 ruby-macho。
修改动态库的Load Command
搭建项目工程
我们新建一个文件夹,并创建Gemfile文件,在Gemfile中引入Ruby调试的必要库和ruby-macho
Gemfile:
source 'https://rubygems.org'
gem 'ruby-debug-ide'
gem 'debase'
gem 'rexml'
gem 'ruby-macho'
gem 'solargraph'
接下来,将 libAFNetworking.dylib文件放入根文件夹下的bin目录下,目录结构入下图所示:
查看动态库的依赖信息
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
# 所有关于动态库的信息, 该动态库所依赖的动态库
file_dylibs = MachO::Tools.dylibs(macho_path_dylib) //3
file_dylibs.each do |dylib|
puts dylib
end
输出结果:
/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/WebKit
- 1,引入
machoruby库。 - 2,将动态库拷贝一份。
- 3,查看
动态库或者可执行文件的信息,可以查看该动态库依赖的其他库文件。
修改rpath
关于动态库中rpath的含义,可以参考这篇文章动态库原理。
1,首先,我们先来查看动态库里面的rpath值:
copy = MachO::MachOFile.new(macho_path_copy_dylib)
origin = MachO::MachOFile.new(macho_path_dylib)
puts "查看 rpath : -- copy ---- #{copy.rpaths} ----- origin ------: #{origin.rpaths}"
输出结果:
查看 rpath : -- copy ---- ["@executable_path/Frameworks", "@loader_path/Frameworks"] ----- origin ------: ["@executable_path/Frameworks", "@loader_path/Frameworks"]
2,修改 rpath 值
# 修改 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 ------: #{origin.rpaths}"
输出结果:
modify rpath >>>>>>: ["@executable_path/Frameworks", "@loader_path/Frameworks/LY"] ----- origin ------: ["@executable_path/Frameworks", "@loader_path/Frameworks"]
从这里我们可以看出,我们已经将libAFNetworking_copy.dylib中的@loader_path/Frameworks的值,成功修改为 @loader_path/Frameworks/LY。
3,添加 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 ------: #{origin.rpaths}"
输出结果:
add rpath >>>>>: ["@executable_path/Frameworks", "@loader_path/Frameworks/LY", "@loader_path/Frameworks/LY1/LY2"] ----- origin ------: ["@executable_path/Frameworks", "@loader_path/Frameworks"]
现在在副本动态库中,我们已经成功的添加了一个新的rpath。
4,删除 rpath
# 删除 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}"
输出结果:
delete rpath >>>>: ["@executable_path/Frameworks", "@loader_path/Frameworks/LY"] ------origin-----: ["@executable_path/Frameworks", "@loader_path/Frameworks"]
以上就是 ruby-macho在修改Mach O文件的一个简单的应用实现了。完整的代码如下:
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 所有关于动态库的信息, 该动态库所依赖的动态库
file_dylibs = MachO::Tools.dylibs(macho_path_dylib)
file_dylibs.each do |dylib|
puts dylib
end
# 查看 rpath
copy = MachO::MachOFile.new(macho_path_copy_dylib)
origin = MachO::MachOFile.new(macho_path_dylib)
puts "查看 rpath : -- copy ---- #{copy.rpaths} ----- origin ------: #{origin.rpaths}"
# 修改 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 ------: #{origin.rpaths}"
# 添加 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 ------: #{origin.rpaths}"
# 删除 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}"