打印的是当前的ui树,随便找一个节点(树的中间,为什么要在中间,大家可以思考下),copy它的内存地址,例如 0x14da3f000
执行:[#0x14da3f000 nextResponder]会输出当前节点的下一级事件响应链,然后对输出节点再次调用 nextResponder,直到找到它的视图控制器 xxxcontroller:
看到了吧,微信的聊天页对应的类名是 BaseMsgContentViewController。
3、追踪神器 - logify目前为止我们已经锁定了大致的突破口,下面还需继续追踪,找到这个类里面的消息处理函数,这里的思路就是通过向群里发送一个消息,然后观察 controller中哪些方法被调用了。
第三个工具 Logify就是干这个事情的,它是 theos的一个组件,和 theos一起安装在 pc端的,在 pc的终端输入:
logify.pl /path/to/BaseMsgContentViewController.h > /out/path/to/Tweak.xm打开生成的 tweak.xm文件,可以看到它其实就是 hook了这个类所有的方法,在方法中注入了 nslog,打印方法的入参和返回值,最后把这个文件用 theos打包并安装到手机中,再次向群里发消息,手机连上 xcode观察手机控制台输出。
输出内容很多,需要仔细过滤一下,例如我们发的消息是一个文本“test”,在控制台搜索它,你会在它附近找到下面这个函数调用:
addMessageNode:layout:addMoreMsg从函数名字来看,这个应该就是用来处理消息数据的,从表面来看我们已经找到消息的拦截点了,但是大家想一下,如果我们hook这个方法,在里面自动抢红包,会有什么致命的缺陷?
老司机们已经看出来了吧,这个方法是 BaseMsgContentViewController类里面的,而这个类进入聊天页面才会被创建。
hook这里会有两个缺陷:
第一,必须进特定的群的聊天页面才能生效;
第二,两个群同时有红包来,没法并发的抢。
为了追求更加上流的功能,我们需要再向上追溯消息的源头,最好 hook那种微信启动后就存在的对象,怎么追溯呢?
我的思路是通过在这个方法中设置断点,通过调用栈,来找到上层的调用者。
4、反汇编工具——hopper & 断点调试工具——lldb + debugserver第五个工具 lldb + debugserver顾名思义,debugserver是手机端的(只要你的手机有连过 xcode进行 debug,这个玩意就自动有了),用于监听 pc端 lldb的连接,来实现远程调试。
这个工具要和第四个 hooper(反汇编工具)结合起来用。
首先 ssh进手机的终端,输入:
debugserver *:19999 -a WeChat监听 lldb的连接
然后打开pc的终端,启动 lldb并连接:
lldb process connect connect://deviceIP:19999如果连接成功,我们就正式进入 debug状态了。
那么问题来了,要精确的设置断点,必须知道这个函数的内存地址,这个内存地址怎么搞出来呢?
有个公式:
内存地址=进程内存基地址+函数在二进制中的偏移量上面我们已经连上了 lldb调试环境,获取基地址在 lldb中输入下面的命令:
image list -o -f这时会输出很多行数据,找到文件名为 WeChat的模块地址,这里第一行就是了:
偏移量需要借助 hooper,pc端的反汇编利器,用 hooper打开微信的二进制文件,等几分钟,反汇编完成后,在搜索框输入刚找到的函数名: addMessageNode,定位到相应的汇编代码,第一列就是偏移量了:
两个参数都找到后,在lldb中输入:
br s -a ‘基地址+偏移量’然后用 “br l” 确认一下断点是否设置成功