微信版本: WeChat 6.5.20 (计算ASLR偏移,是之前版本;不同版本的偏移地址不一样)
砸壳获取头文件
找到bundle路径:
登录到iPhone,查看微信的进程信息
1 | ssh root@192.168.2.24 |
从进程信息里获取微信bundle的路径
1 | 3079 ?? 0:41.37 /var/containers/Bundle/Application/26F5C9BE-61AB-468F-B2E8-9AC2DBD49F40/WeChat.app/WeChat |
获取沙盒路径:
通过cyscript获取微信的沙盒路径,如果没有cy#那么点击进入微信:
1 | cycript -p WeChat |
注入微信进程之后,NSHomeDirectory()输出沙盒路径
1 | cy# NSHomeDirectory() |
下载dumpdecrypted砸壳工具,编译成dylib包
克隆源码,并且编译生成一个dumpdecrypted.dylib
1 | git clone https://github.com/stefanesser/dumpdecrypted.git |
注入微信获取解密的包
scp将dumpdecrypted.dylib拷贝到iPhone
1 | scp dumpdecrypted.dylib root@192.168.2.24:/tmp |
iPhone里进入微信沙盒的Documents目录,拷贝dumpdecrypted.dylib到Documents目录
1 | cd /var/mobile/Containers/Data/Application/0A361401-3880-4C73-862A-8E06F4B7328D/Documents |
通过上面得到的bundle中WeChat包文件,注入微信。注意如果输出Killed: 9那么切换到mobile用户
1 | su mobile |
输出信息:
1 | mach-o decryption dumper |
上面信息结束之后,在Documents目录下有个WeChat.decrypted文件
获取头文件信息
在mac上拷贝iPhone的解密的微信包文件
1 | scp root@192.168.2.24:/var/mobile/Containers/Data/Application/0A361401-3880-4C73-862A-8E06F4B7328D/Documents/WeChat.decrypted . |
class-dump 获取所有的微信头文件到WXHeaders目录
1 | class-dump -s -S -H WeChat.decrypted -o WXHeaders/ |
获取微信bundle id : com.tencent.xin
查看签名信息:codesign -dvvv WeChat.decrypted
1 | Executable=/Users/leaf/yy/project/redpocket/WeChat.decrypted |
创建Tweak工程
调用theod: /opt/theos/bin/nic.pl
选择tweak,然后输入相关信息:
1 | //项目名称 |
自动安装配置Makefile
1 | #debug=0是release包 |
定位视图
安装Reveal:安装mac客户端,iPhone通过Cydia安装Reveal Loader
通过cycript
注入:cycript -p WeChat
通过recursiveDescription输出View层级信息
1 | [[UIApp keyWindow] recursiveDescription].toString() |
找到一个ViewController上面的UIView:<UIView: 0x12f09d930; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x12f2567e0>>,查看响应者
1 | cy# [#0x12f09d930 nextResponder] |
定位 BaseMsgContentViewController 消息响应方法
BaseMsgContentViewController头文件所有的方法被触发打印信息
1 | /opt/theos/bin/logify.pl ./WXHeaders/BaseMsgContentViewController.h > Tweak.xm |
编译安装
注释掉//- (void).cxx_destruct { %log; %orig; }方法,并且在编译中,注释掉所有报错的方法,报错的最主要的原因是找不到头文件。
安装成功后查看log信息
发送消息,定位和消息相关的方法
1 | -[<BaseMsgContentViewController: 0x137904600> addMessageNode:{m_uiMesLocalID=15, m_ui64MesSvrID=4691907035794540423, m_nsFromUsr=wxi*m21~19, m_nsToUsr=wxi*712~19, m_uiStatus=4, type=1, msgSource="<msgsource><sequence_id>690750074</sequence_id></msgsource>"} layout:1 addMoreMsg:0] |
根据log信息,可以很容易得出addMessageNode是我们要找的
通过lldb动态调试
iPhone连接xcode,iOS上会自动在/Developer/usr/bin/目录下面生成调试工具debugserver
debugserver瘦身和重新签名,并放入iPhone /usr/bin /目录下
1 | #mac上拷贝debugserver |
启动调试(目的: 找出接受消息的类,不受页面的限制,单例)
在iPhone启动服务
1 | debugserver *:6666 -a "WeChat" |
mac lldb连接debugserver
1 | lldb |
调试相关命令
1 | #查看所有断点 |
计算地址
地址相关计算逻辑
1 | 偏移后模块基地址 = 偏移前模块基地址 + 模块的ASLR偏移 |
查看ASLR偏移
1 | (lldb) image list -o -f | grep WeChat |
通过Hopper查看addMessageNode的函数基地址
1 | -[BaseMsgContentViewController addMessageNode:layout:addMoreMsg:]: |
偏移后符号基地址 = 0x00000000000a4000 + 0x0000000101c8bf4c
调试微信发送消息
lldb 添加第一个断点:br s -a '0x00000000000a4000+0x0000000101c8bf4c'
注意:在进入好友聊天界面的时候,会多次调用断点,所以进入是删除断点,然后再添加。
发送消息之后,断点停留。然后bt查看堆栈信息,最后c继续
1 | (lldb) bt |
查看堆栈信息可以的得出:与WeChat相关的有四条信息
计算四条信息的地址:
1 | 偏移后符号基地址 = 符号所在模块的ASLR偏移 + 偏移前符号基地址 |
通过Hopper和计算出的(偏移前符号基地址)查看相关的方法,Hopper中使用快捷键G,跳转到某一地址。查看地址不是对应地址,而是地址相关的地址。
1 | 0x101EF59EC:(内部方法) |
lldb继续添加断点调试,这次在好友列表页打断点。
1 | 0x0000000101d2ff4c: |
通过上面分析的出,是[CMessageMgr MainThreadNotifyToExt:]方法。然后我们hook CMessageMgr类中的所有方法,来找出接受消息的方法。
1 | ➜ WXHeaders ls -ll *CMessageMgr* |
查看日志找出的相关方法:
1 | [<CMessageMgr: 0x127ab9570> CheckMessageStatus:] |
选择方法:[
1 | - (void)AsyncOnAddMsg:(id)arg1 MsgWrap:(id)arg2 { |
输出内容
1 | Sep 29 15:02:44 iPhone WeChat[2394] <Warning>: arg1: __NSCFString, wxid_y9bs6i3qil6m21 |
分析消息 CMessageWrap头文件,根据测试得出结论:
1 | @interface CMessageWrap |
红包相关的方法
点开红包,显示抢红包页面,然后通过cycript查看页面层级:
1 | iPhone:~ root# cycript -p WeChat |
红包相关的页面层级:
1 | | WCRedEnvelopesReceiveHomeView:0x1301296d0 |
调试WCRedEnvelopesReceiveHomeView页面
1 | /opt/theos/bin/logify.pl WXHeaders/WCRedEnvelopesReceiveHomeView.h > Tweak.xm |
日志:
1 | Oct 20 10:50:22 iPhone WeChat[3235] <Notice>: [redpocket] Tweak.xm:8 DEBUG: -[<WCRedEnvelopesReceiveHomeView: 0x13720c6d0> initWithFrame:-- andData:<WCRedEnvelopesControlData: 0x13742e5b0> delegate:<WCRedEnvelopesReceiveControlLogic: 0x13719a0c0>] |
点开红包后调用:
1 | Oct 20 10:50:25 iPhone WeChat[3235] <Notice>: [redpocket] Tweak.xm:5 DEBUG: -[<WCRedEnvelopesReceiveHomeView: 0x13720c6d0> OnOpenRedEnvelopes] |
仔细分析可以得出几个和数据相关的方法,其它基本是UI相关
1 | //WCRedEnvelopesControlData & WCRedEnvelopesReceiveControlLogic 初始化一个红包视图 |
打开红包的操作才是我们需要的,那么我们走起,通过Hopper反编译OnOpenRedEnvelopes
头文件
1 | @interface WCRedEnvelopesReceiveHomeView{ |
日志输出:
1 | Oct 20 15:21:19 iPhone WeChat[3282] <Notice>: [redpocket] Tweak.xm:25 DEBUG: -[<WCRedEnvelopesReceiveHomeView: 0x15e8b0510> OnOpenRedEnvelopes] |
WeChat 6.5.20 分割线,上面是之前版本,偏移地址不一样,逻辑啥的都一样。App Store自动升级真是郁闷啊!
Hopper反汇编打开红包方法(和IDA做对比):
1 | -[WCRedEnvelopesReceiveHomeView OnOpenRedEnvelopes]: |
IDA反汇编打开红包的方法(IDA 调用方法时比Hopper注释更加详细,所以下面使用IDA):
- IDA 在调用方法时,将方法的地址,转换为函数名;看反汇编代码更加清晰
- 调用objc_msgSend方法时: X0存放第一个参数receiver,X1存放第二个参数selector,后面的参数依此类推
- x0~x7常用做参数,x0常用做返回值
- adrp地址生成指令,常用做取方法的地址
- x8常用做间接寻址
- mac终端命令 只在当前目录根据内容(MMServiceCenter)查找相关文件:
mdfind -onlyin . MMServiceCenter
1 | text:0000000100E586E8 ; void __cdecl -[WCRedEnvelopesReceiveHomeView OnOpenRedEnvelopes](WCRedEnvelopesReceiveHomeView *self, SEL) |
得出的大概伪代码:
1 | //是否是消息发送者 |
接着我们通过上面调用方法的信息,反汇编 WCRedEnvelopesReceiveControlLogic的WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes方法:
1 | text:00000001011FF35C ; void __cdecl -[WCRedEnvelopesReceiveControlLogic WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes](WCRedEnvelopesReceiveControlLogic *self, SEL) |
通过反汇编分析出的OC代码:
1 | CMessageWrap *messageWrap = [self.m_data m_oSelectedMessageWrap]; |
acceptCallback block里面的相关的代码:
1 | WCRedEnvelopesLogicMgr *redEnvelopesLogicMgr = [[MMServiceCenter defaultCenter] getService: [WCRedEnvelopesLogicMgr class]]; |
编写Tweak工程相关的代码,其中点击打开红包后的操作只使用 acceptCallback block里面的操作,其它的涉及到UI操作的省略:
1 |
|
到这里我们会感觉越来越接近了,然后将编写的Tweak.xm运行起来,发送红包已抢成功!
到这我们进行分析WCRedEnvelopesLogicMgr类
/opt/theos/bin/logify.pl ./WXHeaders/WCRedEnvelopesLogicMgr.h > Tweak.xm
1 |
|
运行查看日志:
1 | 打开红包View的日志: |
通过日志分析可知:
-[WCRedEnvelopesLogicMgr ReceiverQueryRedEnvelopesRequest:{}]类似获取红包信息的操作,拆开红包前调用-[<WCRedEnvelopesLogicMgr: 0x1600e9e30> OnWCToHongbaoCommonResponse:<HongBaoRes: 0x1609aa360> Request:<HongBaoReq: 0x160901060>]拆开红包前后都调用-[WCRedEnvelopesLogicMgr OpenRedEnvelopesRequest:{}]拆开红包后调用,是真正决定抢红包的方法
重点分析这三个方法:
1 |
|
拼接参数,编写自动抢红包代码:
1 |
|