iOS注入技巧,深入理解动态库注入与运行时修改
iOS注入技术主要通过动态库注入和运行时修改实现应用行为干预,动态库注入利用DYLD_INSERT_LIBRARIES环境变量或dlopen函数强制加载自定义库,结合fishhook等工具可拦截系统函数调用,典型场景如逆向分析与功能扩展,运行时修改则依赖Objective-C运行时API,通过method_exchangeImplementations交换方法实现热修复(AOP)或功能增强,配合class_addMethod动态添加方法实现无侵入式Hook,关键点包括Mach-O文件结构分析、符号绑定机制理解,需注意系统签名校验(如AMFI)和越狱环境适配,这两种技术广泛用于调试、性能监控及越狱插件开发,但存在稳定性风险,需严格遵循苹果开发者协议。
动态库注入(Dylib Injection)
动态库注入是iOS注入技术中最常见的一种方式,通过将自定义的动态库(.dylib)加载到目标进程中,可以修改或增强目标应用的功能。
1 动态库注入的原理
iOS应用在启动时会加载动态链接库(如UIKit、Foundation等),通过修改Mach-O文件的LC_LOAD_DYLIB
加载命令,可以强制目标应用加载额外的动态库。
2 实现方式
- 使用
DYLD_INSERT_LIBRARIES
环境变量(适用于越狱设备)
在越狱环境下,可以通过设置DYLD_INSERT_LIBRARIES
来注入动态库:DYLD_INSERT_LIBRARIES=/path/to/inject.dylib /var/containers/Bundle/Application/APP/APP
- 修改Mach-O文件(适用于非越狱设备)
使用工具(如yololib
或insert_dylib
)直接修改二进制文件,插入自定义的LC_LOAD_DYLIB
命令。
3 实际案例
假设我们要注入一个动态库来Hook UIAlertView
的显示:
// inject.dylib __attribute__((constructor)) static void entry() { NSLog(@"Dylib Injected Successfully!"); // Hook UIAlertView 相关方法 }
编译后,使用yololib
注入:
yololib TargetApp inject.dylib
Method Swizzling(方法交换)
Method Swizzling是Objective-C运行时(Runtime)提供的强大功能,允许开发者动态替换方法的实现。
1 基本原理
Objective-C的方法调用在运行时通过objc_msgSend
实现,Method Swizzling利用method_exchangeImplementations
交换两个方法的SEL
(选择子)和IMP
(函数指针)。
2 代码示例
#import <objc/runtime.h> @implementation UIViewController (Swizzle) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; SEL originalSelector = @selector(viewDidLoad); SEL swizzledSelector = @selector(swizzled_viewDidLoad); Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); method_exchangeImplementations(originalMethod, swizzledMethod); }); } - (void)swizzled_viewDidLoad { NSLog(@"ViewDidLoad Hooked!"); [self swizzled_viewDidLoad]; // 调用原方法 } @end
这段代码会在所有UIViewController
的viewDidLoad
被调用时打印日志。
3 注意事项
- 只能在
+load
方法中执行Swizzling,避免多线程竞争。 - 确保方法存在,否则可能引发崩溃(可用
class_addMethod
动态添加)。
Fishhook:修改C函数调用
由于Objective-C Runtime无法直接Hook C函数,Facebook开源的fishhook
库提供了一种解决方案,可以动态替换系统C函数的实现。
1 基本原理
fishhook
通过修改Mach-O文件的__DATA.__la_symbol_ptr
段(存储函数指针)来实现Hook。
2 代码示例
#import "fishhook.h" static int (*orig_printf)(const char * __restrict, ...); int my_printf(const char *format, ...) { orig_printf("Hooked: %s\n", format); return 0; } __attribute__((constructor)) static void entry() { rebind_symbols((struct rebinding[1]){{"printf", my_printf, (void *)&orig_printf}}, 1); }
编译成动态库并注入后,所有printf
调用都会被替换为自定义实现。
其他注入技术
1 Frida:动态脚本注入
Frida是一个跨平台的动态代码插桩工具,支持JavaScript/Python脚本注入:
// Frida脚本示例 Interceptor.attach(ObjC.classes.UIAlertView["- show"].implementation, { onEnter: function(args) { console.log("UIAlertView show called!"); } });
适用于动态调试和逆向分析。
2 Cydia Substrate(MobileSubstrate)
越狱环境下常用的Hook框架,提供MSHookFunction
和MSHookMessageEx
等API:
MSHookMessageEx( objc_getClass("UIAlertView"), @selector(show), (IMP)custom_show, &orig_show );
防御注入的手段
为了防止恶意注入,iOS应用可以采用以下防护措施:
- 检查动态库加载:通过
_dyld_get_image_name
遍历已加载的动态库。 - 代码签名验证:确保二进制未被篡改。
- 反调试检测:使用
ptrace(PT_DENY_ATTACH, 0, 0, 0)
防止调试器附加。