optool为macho文件增加动态库

对macho文件有一定理解后,了解下optool是如何给macho文件增加动态库等功能的

optool 源码

环境

macOS 13.4 (22F66)
Xcode 14.3.1

0x0 编译

下载源码

$ git clone --recurse-submodules https://github.com/alexzielenski/optool.git

修改下Deployment Target,比如改成11.0,不修改会报

2025-04-20 11.16.16.png

当然可以从Xcode旧版本里找到libarclite_macos.x复制一个到对应目录下。

⌘ + B后,从Derived Data中找到编译后的二进制文件

2025-04-20 11.20.31.png

libArgumentParser-Static.a 这个静态库主要是解析命令行参数的,而且链接后会在optool中,可以忽略

0x1 命令到源码分析

注入动态库

# optool install -c <command> -p <payload> -t <target>
$ optool install -c load -p 动态库的地址 -t macho文件

编译出一个非常简单的app,用MachOView查看可知Load Comamnds的LC_LOAD_DYLIB加载了Foundaiton,libobjc.A.dylib… UIKit这些系统库

2025-04-20 11.35.29.png

现在追加一个LearnOptionFramework

./optool install -c load -p LearnOptoolFramework.framework/LearnOptoolFramework -t LearnOptool_patch_cmd

2025-04-20 11.37.10.png

再次用MachOView查看,看出Load Commands增加了LearnOptoolFramework

Snip20250420_1.png

源码分析

打开Xcode工程,工程代码结构简单

Snip20250420_2.png

通过启动传参来调试添加动态库的过程

2025-04-20 17.54.16.png

从main函数开始看,前面部分是解析参数的

int main(int argc, const char * argv[]) {
   
   
    @autoreleasepool {
   
   
        BOOL showHelp = NO;

        // Flags
        XPMArgumentSignature *weak = [XPMArgumentSignature argumentSignatureWithFormat:@"[-w --weak]"];
        XPMArgumentSignature *resign = [XPMArgumentSignature argumentSignatureWithFormat:@"[--resign]"];
        XPMArgumentSignature *target = [XPMArgumentSignature argumentSignatureWithFormat:@"[-t --target]={1,1}"];
        ...
        XPMArgumentPackage *package = [[NSProcessInfo processInfo] xpmargs_parseArgumentsWithSignatures:@[resign, command, strip, restore, install, uninstall, output, backup, aslr, help, unrestrict, rename]];

        NSString *targetPath = [package firstObjectForSignature:target];
        ...

上面这部分是建立命令行解析的规则,比如是这样的字符串 [-t --target]={1,1}

XPMArgumentSignature *target = [XPMArgumentSignature argumentSignatureWithFormat:@"[-t --target]={1,1}"];

进入

+ (id)argumentSignatureWithFormat:(NSString *)format, ...
{
   
   
	va_list args;
	va_start(args, format);
    
	XPMArgumentSignature * signature = [XPMArgumentSignature argumentSignatureWithFormat:format arguments:args];
	
	va_end(args);
	
	return signature;
}

这里会用到可变参数

可变参数

  1. va_list args:定义一个指向个数可变的参数列表指针;
  2. va_start(args, format)format是第一个可选参数前的固定参数,va_start 使指针指向第一个可选参数;
  3. va_arg(args, type)返回参数列表中指针args所指的参数,返回类型为type,并使指针args指向参数列表中下一个参数;
  4. va_end(ap) 清空参数列表,并置参数指针ap无效.

按流程走下去主要就是

xpmargs_ScanFormatCtorHead(scanner, foundSwitches, foundAliases, &foundRange, &didFindRange);

...
for (NSString * s in [enclosedString componentsSeparatedByString:@" "]) {
   
   
		if ([s hasPrefix:@"--"]) {
   
   
			[switches addObject:[s substringFromIndex:2]];
		} else if ([s hasPrefix:@"-"]) {
   
   
			[switches addObject:[s substringFromIndex:1]];
		} else {
   
   
			[aliases addObject:s];
		}
	}

xpmargs_ScanFormatCtorTail(scanner, valueRange, didFindRange);

整个要做的是如何识别[-t --target]={1,1},然后命令行传入能匹配成功。

命令行参数

通过NSProcessInfo 对象的arguments 获取这次传入的参数信息,

@property (readonly, copy) NSArray<NSString *> *arguments;

打印效果大致如下

<__NSFrozenArrayM 0x600000c00c00>(
xxx/optool,
install,
-c,
load,
-p,
LearnOptoolFramework.framework/LearnOptoolFramework,
-t,
LearnOptool_patch_cmd
)

根据规则解析出targetPath

NSString *targetPath = [package firstObjectForSignature:target];

2025-04-20 15.28.31.png

就是-t 参数传入的

如下所示,接着因为工具支持是否要备份,使用({})匿名函数来返回备份文件路径,target后面加_backup,因为没有使用到忽略。

...
NSBundle *bundle = [NSBundle bu
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值