1、tweak原理分析

给iOSTest创建一个tweak项目,添加一个Alert:

  1. #import <UIKit/UIKit.h>
  2. @interface ViewController
  3. - (void)presentViewController:(id)arg1 animated: (BOOL)arg2 completion:(id)arg3;
  4. @end
  5. %hook ViewController
  6. - (void)viewDidLoad {
  7. %orig;
  8. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  9. UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"Hook" preferredStyle:UIAlertControllerStyleAlert];
  10. [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
  11. [self presentViewController:alert animated:YES completion:nil];
  12. });
  13. }
  14. %end

新增的hook代码最终被打包成dylib文件保存在iPhone的/Device/Library/MobileSubstrate/DynamicLibraries/路径下,在App启动时通过Cydia Substrate加载。如果想把App和插件一起重新打包,安装到非越狱手机上,就需要将插件dylib和.app包一起重签名。

2、动态库签名

2.1、动态库注入

将tweak_test.dylib放到.app包内:
截屏2022-06-07 22.21.20.png
利用otool指令查看可执行文件引用的动态库:$ otool -L iOSTest

  1. iOSTest:
  2. /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1860.0.0)
  3. /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
  4. /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.120.1)
  5. /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1860.0.0)
  6. /System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 5610.0.0)

也可以通过 Mach-O - Load Commands 查看动态库引用。

发现可执行文件默认不会引用.app包内的动态库,可以使用 insert_dylib 库将动态库注入到Match-O文件中,使用方法:$ insert_dylib 动态库加载路径 Mach-O文件,有两个常用参数选项:—weak,即使动态库找不到也不会报错;—all-yes,后面所有的选择都为yes。

insert_dylib下载后需要进行编译然后把可执行文件放到 /usr/local/bin 路径下。 insert_dylib的本质是往Mach-O文件的Load Commands中添加了一个LC_LOAD_DYLIB或LC_LOAD_WEAK_DYLIB。

插入tweak_test.dylib动态库:
$ insert_dylib @executable_path/tweak_test.dylib iOSTest —all-yes —weak iOSTest

@executable_path是环境变量,代表动态库所在目录。 —weak代表若引用,避免找不到动态库导致崩溃。 第一个iOSTest是可执行文件名称,第二个iOSTest是导出名称,执行完毕后回覆盖原文件。

通过otool指令查看可执行文件:$ otool -L iOSTest

  1. ...
  2. @executable_path/tweak_test.dylib (compatibility version 0.0.0, current version 0.0.0, weak)

可以发现,已经将动态库添加到了Mach-O文件中。

2.2、更改动态库加载地址

2.2.1、CydiaSubstrate

通过Theos开发的动态库插件(dylib),默认都依赖于CydiaSubstrate(/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate),将动态库插件打包到ipa的同时,需要修改CydiaSubstrate的加载地址。
通过otool指令查看tweak_test.dylib引用的动态库:$ otool -L tweak_test.dylib

  1. ...
  2. /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)
  3. ...

可以发现tweak_test.dylib中引用了CydiaSubstrate.framework

2.2.2、更改动态库的加载地址

因为tweak_test.dylib中引用CydiaSubstrate使用的是iPhone中的绝对地址,需要调整为可以正常访问的相对路径。将CydiaSubstrate也放入.app包中:
截屏2022-06-07 22.19.49.png
可以使用install_name_tool指令修改Mach-O文件中动态库的加载地址,使用方法:$ instsall_name_tool -change 旧地址 新地址 Mach-O文件,修改tweak_test.dylib中的CydiaSubstrate地址:
$ install_name_tool -change /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate @loader_path/CydiaSubstrate tweak_test.dylib
再通过otool指令查看引用路径:$ otool -L tweak_test.dylib

  1. ...
  2. @loader_path/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)
  3. ...

可以看到CydiaSubstrate的引用地址已经更新了。

2.2.3、环境变量

@executable_path 代表可执行文件所在目录
@loader_path 代表动态库所在目录

3、重签名

3.1、对tweak_test重签名

$ codesign -fs 21F086108036249F734ED29537C51EB1862233D4 tweak_test.dylib

3.2、对CydiaSubstrate重签名

$ codesign -fs 21F086108036249F734ED29537C51EB1862233D4 CydiaSubstrate

3.3、对App包重签名

使用iOS App Signer对.app包进行重签名后,就可以安装到非越狱设备上了。
image.png