Method Swizzle
利用OC的Runtime特性,动态改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变的目的。主要用于OC方法。
关于Runtime,如果大家不了解,可以看看Cooci老师的文章——iOS底层原理(二):Runtime研究(一),简单了解一下。
在OC中,SEL 和 IMP 之间的关系,就好像一本书的“目录”。
SEL 是方法编号,就像“标题”一样。
IMP是方法实现的真实地址,就像“页码”一样。
他们是一一对应的关系
SEL(标题)————————IMP(页码)
Runtime提供了交换两个SEL和IMP对应关系的函数。通过函数交换、改变两个SEL和IMP关系的技术,我们称之为Method Swizzle(方法欺骗)。
多种Hook方式
- class_addMethod
- class_replaceMethod
- method_setImplementation
代码示例
一、注册
之前我们有讲过代码注入,本文不再过多赘述,需要的同学,点击iOS逆向——shell重签名及代码注入跳转。那么上手直接撸代码啦。
1、新建项目,生成新的证书和描述文件,在手机上跑一遍,保证描述文件可以正确安装到手机中。
2、运行Xcode,脚本重签APP
3、TARGETS创建Framework,并创建.h .m,这里我们命名Inject
4、运行app, lldb动态调试,分析代码逻辑。
5、如下图所示,因为Xcode版本不同,有的Target 和 Action 会直接显示类名,如果不直接显示类名的,可以用po命令+对象地址看到ClassName。p是执行指令,o是object的意思。

6、找到相关名称,就可以用class-dump这个工具把二进制文件所有的类的描述copy出来(相当于头文件,但是不仅仅是头文件)
class-dump -H 二进制文件 -o 目标文件夹7、根据clas-dump导出的文件,考虑相关逻辑。关于查看class-dump导出的文件,建议使用轻量级的sublime,使用更快速。
8、那么接下来就是代码了。如下图所示:

9、运行Xcode,重签app,这里要注意一点,上一章我写的脚本,在最后一行'#代码注入'是注释状态。那么这次运行放开,才能注入成功。Framework的名字也要改成代码中对应的名字。
10、铛铛铛铛

二、登录
同理,登录的的业务逻辑我们要结合动态调试(lldb)以及静态分析(class-dump导出的文件)

- class-dump导出文件

2、根据文件分析业务逻辑,找出相关类。先判定控制器,是WCAccountBaseViewController,通过找WCAccountBaseViewController的属性,判断WCAccountTextFieldItem *_textFieldUserPwdItem与密码相关。

通过WCAccountTextFieldItem找其父类WCBaseTextFieldItem,

在WCBaseTextFieldItem下,查到WCUITextField *m_textField。以上仅是分析,但不能判断是否就是我们需要的UITextField,所以首先,我们要lldb调试。

3、lldb调试如下

4、所以最终我们需要拿到textField,最后textField.text拿到pwd.
(1)方法交换


这是在inject类中增加新的方法,再实现方法交换,但WCAccountMainLoginViewController并不存在Maxy_onNext调用方法,要想真正的根据业务需求实现方法交换,需要给WCAccountMainLoginViewController增加新的方法,在inject实现方法交换。

这样并不破坏wc的登录逻辑。关于参数type,请查看官方文档,有明确的说明。
(2)方法替换

(3)setIMP和getIMP(推荐)

三种不同的方法,都能实现。最后推荐使用setIMP、getIMP。如果我哪里写的不对、不清楚,还希望你能指正出来,我们共同探讨进步,如果你喜欢此文章,就动一动小手点个赞吧。