1、tweak原理分析
给iOSTest创建一个tweak项目,添加一个Alert:
#import <UIKit/UIKit.h>
@interface ViewController
- (void)presentViewController:(id)arg1 animated: (BOOL)arg2 completion:(id)arg3;
@end
%hook ViewController
- (void)viewDidLoad {
%orig;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"Hook" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
});
}
%end
新增的hook代码最终被打包成dylib文件保存在iPhone的/Device/Library/MobileSubstrate/DynamicLibraries/路径下,在App启动时通过Cydia Substrate加载。如果想把App和插件一起重新打包,安装到非越狱手机上,就需要将插件dylib和.app包一起重签名。
2、动态库签名
2.1、动态库注入
将tweak_test.dylib放到.app包内:
利用otool指令查看可执行文件引用的动态库:$ otool -L iOSTest
iOSTest:
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1860.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.120.1)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1860.0.0)
/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
...
@executable_path/tweak_test.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
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
...
/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)
...
可以发现tweak_test.dylib中引用了CydiaSubstrate.framework
2.2.2、更改动态库的加载地址
因为tweak_test.dylib中引用CydiaSubstrate使用的是iPhone中的绝对地址,需要调整为可以正常访问的相对路径。将CydiaSubstrate也放入.app包中:
可以使用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
...
@loader_path/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)
...
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包进行重签名后,就可以安装到非越狱设备上了。