动态库

155 阅读5分钟

动态库

image.png

执行如下脚本,此处不再说明,前面静态库分析的文章里解释过。

 echo "编译test.m--test.o"

 clang -target x86_64-apple-macos11.3 \

 -fobjc-arc \

 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \

 -I./dylib \

 -c test.m -o test.o


 pushd ./dylib

 echo "编译TestExample.m--TestExample.o"


 clang -x objective-c \

 -target x86_64-apple-macos11.3 \

 -fobjc-arc \

 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \

 -c TestExample.m -o TestExample.o

 echo "编译TestExample.m--libTestExample.dylib"


 # -dynamiclib 动态库 编译为

 clang -dynamiclib \

 -target x86_64-apple-macos11.3 \

 -fobjc-arc \

 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \

 TestExample.o -o libTestExample.dylib


 # 1 官方 Xcode->静态库 2 ar -rc libTestExample.a TestExample.o


 libtool -static -arch_only x86_64 TestExample.o -o libTestExample.a

 
 popd

 echo "链接libTestExample.dylib---test"

 clang -target x86_64-apple-macos11.1 \

 -fobjc-arc \

 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \

 -L./dylib \

 -lTestExample \

 test.o -o test

  • 运行脚本 如果运行脚报权限相关的错误的话,执行 如下命令

chmod +x ./build.sh 给与权限

  • 运行可执行文件

lldb -file test 再运行 r 运行结果如下

image.png

分析

静态库.o的合集直接将.o文件改成静态库可以运行,但是动态库是一个链接编译最终产物。这也就意味着静态库可以通过链接变成动态库

修改脚本


# Xcode->静态库

libtool -static -arch_only x86_64 TestExample.o -o libTestExample.a

echo "编译TestExample.m --- libTestExample.dylib"

# -dynamiclib: 动态库

# dylib 最终链接产物 -》

ld -dylib -arch x86_64 \

-macosx_version_min 11.3 \

-syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \

-lsystem -framework Foundation \

-all_load \

libTestExample.a -o libTestExample.dylib

  • 再次运行可执行文件 同样报错 错误一样

总结

  • 静态库是.o文件的合集
  • 动态库是.o文件链接过后的产物
  • 静态库可以通过链接生成动态库
  • 动态库也就是最终产物,这也是动态库无法合并原因

动态库解析

引入一个概念 tbd文件

image.png

引入头文件链接路径 image.png

或者直接将SYCSSColor.tbd文件直接拖到项目

俩种方式代码都编译成功

tbd文件

  • tbd全称是text-based stub libraries,本质上就是一个YAML描述的文本文件
  • 他的作用是用于记录动态库的一些信息,包括导出的符号动态库的架构信息动态库的依赖信息
  • 用于避免真机开发过程中直接使用传统的dylib
  • 对于真机来说,由于动态库都是在设备上,在Xcode上使用基于tbd格式伪framework可以大大减少Xcode的大小

tbd格式

image.png

  • exports导出的意思
  • symbols是符号的意思,也就意味着11-14行都是导出符号
  • objc-classes是objc类的集合

生成tbd

Xcode的Build Settings搜索text

image.png

原理:就是通过拼上一些参数,来扫描Headers里面的头文件,然后把这个符号写到文件里去

tbd总结

通过上面我们可以知道我们用脚本去链接库的是用到-L,-l链接是符号,也就是我们只需要知道符号所在的位置不需要知道源码位置

运行肯定会报错

运行的时候,由dyld动态加载动态库,在加载的时候,它会去找这个符号真实地址的时候,找不到直接闪退报错,而静态库编译的时候就已将符号放在一起,不会动态加载

动态库加载

image.png

  • 这里的Mach-o相当于我们的可执行文件Test,Test的Mach-o有个专门的LC_LOAD_DYLIB,它里面有我们需要用到的动态库路径,当它找不到这个路径的时候就会报错`

终端执行如下命令

// 查找使用的动态库
otool -l test | grep 'DYLIB'
// 查找到使用的动态库 继续显示 5行
otool -l test | grep 'DYLIB' -A 5

//-A是向下展示,向上展示时-B

image.png

动态库中name字段就是该动态库路径,但是我们导入的动态库TestExample路径只有一个名字,别的什么都没有,这样肯定找不到TestExample

动态库路径

动态库有一个专门的地方保存自己的路径,也就是说动态库的路径是保存在自己的Mach-o中的,下面我们就来查看下这个路径

image.png

有个命令来更改路径名称:install_name_tool,改变动态库install name

执行如下命令

image.png

再来执行一次build.sh脚本,重新生成test文件,在查看下引入的动态库

image.png

再运行可执行文件

image.png

动态库路径优化

绝对路径有一个问题,当我们做好SDK后给别人使用,那么这个路径就会改变,很不方便。

@rpath

@rpath:Runpath search Paths! dyld搜索路径。运行时@rpath指示dyld按顺序搜索路径列表,以找到动态库@rpath保存一个或多个路径的变量! 也就是谁连接我谁给我提供@rpath

image.png

test给TestExample提供@rpath 方式有俩种如下

image.png

替换rpath,下面的是添加rpath到指定的Mach-o

image.png

lldb -file test 执行文件

image.png

路径继续优化 @executable_path

@executable_path @loader_path

  • @executable_path:表示可执行程序所在的目录,解析为可执行文件的绝对路径。
  • @loader_path:表示被加载的Mach-O所在的目录,每次加载时,都可能被设置为不同的路径,由上层指定

@executable_path

@executable_path,不管在谁的电脑上它都指向执行程序所在的路径

image.png

image.png

image.png

@loader_path

举例

test中使用的framework中包含TestExample.framework,而TestExample.framework的framework中包含TestExampleLog.framework

image.png

修改TestExample.framework的脚本

image.png

image.png

手动看一下

image.png

运行

image.png

再次改脚本

image.png

image.png

cocoaPod

为了加深@executable_path印象,我们可以看看cocoaPods的xcconfig文件

image.png

当我们编译代码,看下可执行文件的包内容,我们发现动态库都会存放在framework文件中,也就是上面设置的文件里

image.png

总结

链接动态库,一定要指定好路径,否咋就会报错。

  • 我们介绍了通过install_name_tool更改路径
  • 为了优化路径,我们引入@rpath
  • -rpath lod new 是替换路径-add_rpath是将路径添加到指定位置
  • 为了再优化,我们又引入了@executable_path@loader_path

上面讲了可以替换路径,那么就想到了破解,因为我们可以改变路径,将我们自己写的动态库作为目标软件的依赖达到破解的目的。我们这么做事改变了Mach-o,之前讲过Mach-o只有签名后才会被苹果系统承认,所以再破解软件是都会调用一句命令:code sign --force --deep --sign - 这句命令也就是强制打一个签名,后面再详细研究。