methodSwizzling原理分析

    科技2022-07-20  91

    最近看了一些关于iOS逆向工程的基础知识和某些开源代码。 根据越狱CydiaSubStrate关于MSHookMessageEx挂钩信息功能补充部分API介绍: Objective-C提供了好用的high_level runtime API,允许开发者使用class_getInstanceMethod, method_setImplementation和更强大的method_exchangeImpletation来swizzle四维索引重排方法并改变替换功能执行。 虽然API非常好用但API却不能胜任更复杂的情况。**比方说在继承层次上的不同level上去hook 同一个message,那么就会出现顺序处理顺序研究的问题。 ** 当使用instrument转换时,class会被修改,并且没有初始化(“initialized”)。既改变了target program的顺序,也使得hook初始化时有序变得不可能。总而言之,Objective-C runtime API 的实现方式改变了。Substrate越狱分发平台提供了更好的API : void MSHookMessageEx(Class _class, SEL message, IMP hook, IMP *old); 不需要初始化一个class并且保证在继承层次上使用正确的implementation. 根据NewRelic的文章,假如有两个方法:

    - (void) originalMethod; - (void) swizzle_originalMethod;

    如果直接使用void method_exchangeImplementations(Method m1, Method m2) , 而且恰巧代码的实现如下:

    - (void) originalMethod //m1 { assert([NSStringFromSelector(_cmd) isEqualToString:@“originalMethod”]); //this `assert` fails after swizzling //if using method_exchangedImplementations() //… }

    正确的方式是去写C函数,并使用method_setImplementation() 将 C 函数强转成IMP。 这将避免Objective-C传递像一个新的selectorname这样额外的信息。 不要忘记:所有的Objective-C方法都带有2个隐藏的参数(这一点,当我们用Hopper或IDA来逆向的时候很容易看到):一个指向自身的引用id self和一个 method selector SEL _cmd。 如果要使用返回void的IMP, 那么就必须强转。这是因为ARC假设所有的IMP会返回id,并尝试 retain void和基本类型数据。

    IMP anImp; //represents objective-c function // such as -UIViewController viewDidLoad; ((void(*)(id,SEL))anImp)(self,_cmd); //call with a cast to prevent // ARC from retaining void.

    使用MethodSwizzling是最后的手段。

    Processed: 0.010, SQL: 8