58fb01ef5f6711e0dafe8343b0d0d734
项目实战篇:微信抢红包

1.概述

风险提醒:在进行下面的操作时,要做好账号被封的心理准备,如果不想账号被封,那么下面的操作,做一个了解就行,重点是学会分析问题的思路。

我们知道,微信有抢红包的功能。在会话界面收到一个红包消息的时候,点击打开是一个红包信封的页面,里面有一个【开】按钮,点击【开】按钮,就可以真正的抢红包。

我们来捋一下思路:要想抢红包,首先我们要找到收消息的方法,在收到消息的时候,判断如果是红包消息,则调用抢红包的代码。

2.准备工作

2.1 工具和基础知识

2.2 初始工作

  • 第一步:头文件导出。通过 class-dump 指令,导出微信头文件。
class-dump -H WeChat -o GofWechatHeader
  • 第二步:将第一步导出的头文件的文件夹,直接拖到 Sublime 中备用(也可以拖到 XCode 中,但 XCode 中会慢很多),同时选择 Sublime 的语言为【Objective-C】。

  • 第三步:使用【MonkeyApp】(参看《工具篇:逆向工具-MonkeyDev》)模板新建一个工程,并配置好证书和账号,将准备好的微信的 IPA 文件,拷贝到指定的文件夹。

  • 第四步:为了更好的进行 UI 分析,可以配置 Pod,在工程根目录中,使用下面的指令,初始化 Pod:

pod init
  • 第五步:添加 UI 分析工具【Lookin】,配置好的【Podfile】文件如下图所示(当然也可以根据实际需要,添加其他的一些库):
source 'https://github.com/CocoaPods/Specs.git'
# platform :ios, '9.0'

target 'GofWechat' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for GofWechat

end

target 'GofWechatDylib' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for GofWechatDylib
  pod 'LookinServer', :configurations => ['Debug']

end
  • 第六步:使用 Xcode 打开工程,同时可以打开【LookIn】,辅助进行 UI 的分析。

  • 第七步:使用【IDA】打开微信的【可执行文件】,以方便后面的汇编分析(打开可执行文件解析耗时较长,建议打开之后保存)。

至此,准备工作就差不多了,下面进行分析。

3.抢红包分析和实现

3.1 红包消息分析

我们知道,抢红包是在会话界面打开红包消息,然后点开红包,进行抢红包操作。因此,我们首先来看一下这个页面的相关代码。

  • 第一步:运行工程,进入会话界面,可以直接通过【Xcode】或者【LookIn】,查看到会话界面类为【BaseMsgContentViewController】。
  • 第二步:使用【Sublime】,打开微信头文件的文件夹,通过【Cmd+Shift+F】,搜索「@interface BaseMsgContentViewController」,查看「BaseMsgContentViewController」的类定义。
  • 第三步:Hook 类【BaseMsgContentViewController】里的所有方法,看一下收到消息时,都调用了哪些方法。从【BaseMsgContentViewController】的头文件中可以看到,这个类里面的方法有很多,如果逐一添加的话,会花费很多时间,这时我们可以借助工具【/opt/theos/bin/logify.pl】,来自动生成 Hook 文件。
logify.pl /Users/ligaofeng/Desktop/BaseMsgContentViewController.h > ./GofMsgContentVCHeader.xm
  • 第四步:将上一步生成的 xm 文件,拖到工程中。编译之后,会生成一个 GofMsgContentVCHeader.mm 文件,也将这个文件拖入工程,Target 选择 dylib。再编译一次,会发现有很多的报错,因为很多类型,在新的工程是无法识别的。这时候可以用这种方式:将整个微信的头文件,导入到工程。这个会执行较长时间,但不太建议这样处理,这时候我们可以换一种方式。
  • 第五步:删掉第四步生成的【.mm】和【.xm】文件,在【MDConfig.plist】文件,使用【MonkeyApp】中集成的【Hook】方式进行整个类的【Hook】。参考【OCMethodTrace】。
  • 第六步::收到微信消息时,查看打印出来的调用方法,可以看到有很多,这里我们重点看一下和【message】相关的。
- (void)addMessageNode:(id)arg1 layout:(_Bool)arg2 addMoreMsg:(_Bool)arg3;
  • 第七步:在【GofWechatDylib.xm】文件中单独【Hook】消息相关的方法。
%hook BaseMsgContentViewController

- (void)addMessageNode:(id)arg1 layout:(_Bool)arg2 addMoreMsg:(_Bool)arg3 {
    %orig;
}

%end
  • 第八步:添加断点,运行工程,在【LLDB】中查看相应的参数。从【LLDB】结果可以看到,【arg1】是与消息有关系的结构对象,并且每条消息都会调用这个方法。在断点的时候,我们看一下函数调用栈,发现函数调用栈看不到具体的方法,这是因为没有符号表。

  • 第九步:使用工具【restore-symbol】,恢复符号表。

./restore-symbol WeChat_arm64 -o WeChat_restore

恢复之后,将生成的【WeChat_restore】修改名称成【WeChat】,然后拷贝到微信的【app】文件里面,并进行替换。重新运行工程,可以看到符号表已经恢复了。

  • 第十步:重新断点查看收到消息时的堆栈,可以看到这时候调用的相关方法。
  • 第十一步:Hook 上面堆栈中的三个方法,然后断点,在收到消息时,查看方法的执行。
%hook BaseMsgContentLogicController

- (void)DidAddMsg:(id)arg1 {
    %orig;
}

- (void)OnAddMsg:(id)arg1 MsgWrap:(id)arg2 {
    %orig;
}

%end

%hook CMessageMgr

- (void)MainThreadNotifyToExt:(id)arg1 {
    %orig;
}

%end
  • 第十二步:通过断点,发现每次收到新消息时,都会调用一次【MainThreadNotifyToExt: 】,参数 org1 打印结果如下所示:
(lldb) po arg1
{
    1 = 1;
    2 = LeeGof;
    3 = "{m_uiMesLocalID=8, m_ui64MesSvrID=438239389382184533, m_nsFromUsr=Gof*132~32, m_nsToUsr=wxi*a38~15, M_UIStatus=3, type=1, msgSource=\"<msgsource><sequence_id>7003982112</sequence_id></msgsource>\"}"
}
  • 第十三步:从上面参数的值大概猜测,类【CMessageMgr】是消息管理者,我们【Hook】整个【CMessageMgr】,然后跟踪一下,收到消息时,这个类里都有哪些方法执行了。重新运行程序,当收到消息时,可以看到调用了很多方法。根据名称,我们重点来分析一下这个方法:
%hook CMessageMgr

- (void)onNewSyncAddMessage:(id)arg1 {
    NSLog(@"%@  %@", arg1, [arg1 class]);
    %orig;
}

%end
  • 第十四步:重新运行程序,可以看到当收到新消息时,程序在后台也会调用这个方法,arg1 的类型为【CMessageWrap】,我们可以在【Sublime】中打开头文件,通过【Command + Shift + F】,搜索 「@interface CMessageWrap」,查看这个类的定义。同时,我们可以尝试发送不同类型的消息:文本、图片、红包等,查看对应的 type 值。经过尝试,可以确定:
    • type=1,表示文本消息;
    • type=3,表示图片消息;
    • type=49,表示红包消息;
    • ...

这样我们就定位到了红包消息的调用代码以及类型,接下来我们要做的是定位抢红包的代码。

补充知识点:恢复符号表

恢复符号表可以借助工具:【restore-symbol】。直接运行这个工程,也可以使用下面的指令生成一个可执行文件:

make restore-symbol

由于【restore-symbol】只能针对单一架构的可执行文件恢复,因此我们需要先处理一下 MachO:

/restore-symbol> lipo -info WeChat
Architectures in the fat file: WeChat are: armv7 arm64
/restore-symbol> lipo -thin arm64 WeChat -output WeChat_arm64
/restore-symbol> lipo -info WeChat_arm64
Non-fat file: WeChat_arm64 is architectures: arm64

然后使用【restore-symbol】恢复:

/restore-symbol > ./restore-symbol WeChat_arm64 -o WeChat_restore

恢复之后,将生成的【WeChat_restore】修改名称成【WeChat】,然后拷贝到微信的【app】文件里面,并进行替换。重新运行工程,可以看到符号表已经恢复了。

3.2 抢红包分析

上面我们已经定位了红包消息的调用代码和类型,接下来我们看看抢红包的代码。

  • 第一步:通过 Lookin,找到如下图所示开红包那个按钮对应的 Target(【WCRedEnvelopesReceiveHomeView】,LLDB 调试可以使用对象的 allTargets 得到) 和 Action(OnOpenRedEnvelopes)。这样我们只要手动调用方法【OnOpenRedEnvelopes】,就能抢红包。现在的 难点 是:这是一个对象方法,首先我们要有这个对象才行,而这个对象是需要有抢红包界面才有,而我们的自动抢红包,是没有这个界面的。假想一下:我们根据需要,自动去创建一系列的页面对象,然后调用抢红包,这整个操作会很复杂。那么还有其他方式吗?这个时候,我们需要分析一下 OnOpenRedEnvelopes 的源码了。
  • 第二步::使用【IDA】分析抢红包的汇编源码。打开 IDA 工具,找到【WCRedEnvelopesReceiveHomeView】类的 【OnOpenRedEnvelopes】方法(在 IDA 中,按住【Control + F】进行搜索)。
  • 第三步:从 IDA 中得到方法【OnOpenRedEnvelopes】的汇编代码,可以看到,这个方法实际上就是 得到两个成员变量:【m_dicBaseInfo、m_delegate】(代理类型可以通过在 Hook 方法 OnOpenRedEnvelopes 时打印看到,这里打印后可以看到类型为 WCRedEnvelopesReceiveControlLogic),使用 m_delegate 调用了【WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes】方法
_text:0000000101157270
__text:0000000101157270 ; =============== S U B R O U T I N E =======================================
__text:0000000101157270
__text:0000000101157270 ; Attributes: bp-based frame
__text:0000000101157270
__text:0000000101157270 ; void __cdecl -[WCRedEnvelopesReceiveHomeView OnOpenRedEnvelopes](WCRedEnvelopesReceiveHomeView *self, SEL)
__text:0000000101157270 __WCRedEnvelopesReceiveHomeView_OnOpenRedEnvelopes_
__text:0000000101157270
__text:0000000101157270 var_60          = -0x60
__text:0000000101157270 var_50          = -0x50
__text:0000000101157270 var_40          = -0x40
__text:0000000101157270 var_30          = -0x30
__text:0000000101157270 var_20          = -0x20
__text:0000000101157270 var_10          = -0x10
__text:0000000101157270 var_s0          =  0
__text:0000000101157270
__text:0000000101157270                 SUB             SP, SP, #0x70
__text:0000000101157274                 STP             X24, X23, [SP,#0x60+var_30]
__text:0000000101157278                 STP             X22, X21, [SP,#0x60+var_20]
__text:000000010115727C                 STP             X20, X19, [SP,#0x60+var_10]
__text:0000000101157280                 STP             X29, X30, [SP,#0x60+var_s0]
__text:0000000101157284                 ADD             X29, SP, #0x60
__text:0000000101157288                 MOV             X19, X0
__text:000000010115728C                 ADRP            X8, #_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_dicBaseInfo@PAGE ; NSDictionary *m_dicBaseInfo;
__text:0000000101157290                 LDRSW           X24, [X8,#_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_dicBaseInfo@PAGEOFF] ; NSDictionary *m_dicBaseInfo;
__text:0000000101157294                 LDR             X0, [X19,X24]
__text:0000000101157298                 ADRP            X8, #selRef_objectForKey_@PAGE
__text:000000010115729C                 LDR             X20, [X8,#selRef_objectForKey_@PAGEOFF]
__text:00000001011572A0                 ADRP            X2, #cfstr_Issender_1@PAGE ; "isSender"
__text:00000001011572A4                 ADD             X2, X2, #cfstr_Issender_1@PAGEOFF ; "isSender"
__text:00000001011572A8                 MOV             X1, X20
__text:00000001011572AC                 BL              _objc_msgSend
__text:00000001011572B0                 MOV             X29, X29
__text:00000001011572B4                 BL              _objc_retainAutoreleasedReturnValue
__text:00000001011572B8                 MOV             X21, X0
__text:00000001011572BC                 ADRP            X8, #selRef_intValue@PAGE
__text:00000001011572C0                 LDR             X22, [X8,#selRef_intValue@PAGEOFF]
__text:00000001011572C4                 MOV             X1, X22
__text:00000001011572C8                 BL              _objc_msgSend
__text:00000001011572CC                 MOV             X23, X0
__text:00000001011572D0                 MOV             X0, X21
__text:00000001011572D4                 BL              _objc_release
__text:00000001011572D8                 LDR             X0, [X19,X24]
__text:00000001011572DC                 ADRP            X2, #cfstr_Hbtype_1@PAGE ; "hbType"
__text:00000001011572E0                 ADD             X2, X2, #cfstr_Hbtype_1@PAGEOFF ; "hbType"
__text:00000001011572E4                 MOV             X1, X20
__text:00000001011572E8                 BL              _objc_msgSend
__text:00000001011572EC                 MOV             X29, X29
__text:00000001011572F0                 BL              _objc_retainAutoreleasedReturnValue
__text:00000001011572F4                 MOV             X20, X0
__text:00000001011572F8                 MOV             X1, X22
__text:00000001011572FC                 BL              _objc_msgSend
__text:0000000101157300                 MOV             X21, X0
__text:0000000101157304                 MOV             X0, X20
__text:0000000101157308                 BL              _objc_release
__text:000000010115730C                 ADRP            X8, #classRef_NSString@PAGE
__text:0000000101157310                 LDR             X0, [X8,#classRef_NSString@PAGEOFF]
__text:0000000101157314                 ADD             W8, W21, #1
__text:0000000101157318                 CMP             W23, #0
__text:000000010115731C                 MOV             W9, #1
__text:0000000101157320                 CINC            W9, W9, LE
__text:0000000101157324                 ADRP            X10, #selRef_stringWithFormat_@PAGE
__text:0000000101157328                 LDR             X1, [X10,#selRef_stringWithFormat_@PAGEOFF]
__text:000000010115732C                 ADRP            X10, #stru_103962208@PAGE
__text:0000000101157330                 ADD             X10, X10, #stru_103962208@PAGEOFF
__text:0000000101157334                 MOV             W11, #2
__text:0000000101157338                 STP             X11, X10, [SP,#0x60+var_40]
__text:000000010115733C                 STP             X9, XZR, [SP,#0x60+var_50]
__text:0000000101157340                 MOV             W9, #5
__text:0000000101157344                 STP             X9, X8, [SP,#0x60+var_60]
__text:0000000101157348                 ADRP            X2, #cfstr_UUUUU_2@PAGE ; "%u,%u,%u,%u,%u,%@"
__text:000000010115734C                 ADD             X2, X2, #cfstr_UUUUU_2@PAGEOFF ; "%u,%u,%u,%u,%u,%@"
__text:0000000101157350                 BL              _objc_msgSend
__text:0000000101157354                 MOV             X29, X29
__text:0000000101157358                 BL              _objc_retainAutoreleasedReturnValue
__text:000000010115735C                 MOV             X20, X0
__text:0000000101157360                 MOV             W0, #0x2DB5
__text:0000000101157364                 MOV             X1, X20
__text:0000000101157368                 MOV             W2, #0
__text:000000010115736C                 MOV             W3, #0
__text:0000000101157370                 BL              sub_102E1B640
__text:0000000101157374                 ADRP            X8, #_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_delegate@PAGE ; WCRedEnvelopesReceiveHomeViewDelegate *m_delegate;
__text:0000000101157378                 LDRSW           X8, [X8,#_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_delegate@PAGEOFF] ; WCRedEnvelopesReceiveHomeViewDelegate *m_delegate;
__text:000000010115737C                 ADD             X0, X19, X8
__text:0000000101157380                 BL              _objc_loadWeakRetained
__text:0000000101157384                 MOV             X19, X0
__text:0000000101157388                 ADRP            X8, #selRef_WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes@PAGE
__text:000000010115738C                 LDR             X1, [X8,#selRef_WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes@PAGEOFF]
__text:0000000101157390                 BL              _objc_msgSend
__text:0000000101157394                 MOV             X0, X19
__text:0000000101157398                 BL              _objc_release
__text:000000010115739C                 MOV             X0, X20
__text:00000001011573A0                 LDP             X29, X30, [SP,#0x60+var_s0]
__text:00000001011573A4                 LDP             X20, X19, [SP,#0x60+var_10]
__text:00000001011573A8                 LDP             X22, X21, [SP,#0x60+var_20]
__text:00000001011573AC                 LDP             X24, X23, [SP,#0x60+var_30]
__text:00000001011573B0                 ADD             SP, SP, #0x70
__text:00000001011573B4                 B               _objc_release
__text:00000001011573B4 ; End of function -[WCRedEnvelopesReceiveHomeView OnOpenRedEnvelopes]
  • 第四步:我们在工程中,可以通过使用下面的代码 Hook 类【WCRedEnvelopesReceiveHomeView】的【OnOpenRedEnvelopes】方法,来进行验证:
@interface WCRedEnvelopesReceiveHomeView
{
    id m_delegate;
    NSDictionary *m_dicBaseInfo;
}

@end

@interface GofWeChatDelegate

- (void)WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes;

@end

%hook WCRedEnvelopesReceiveHomeView

// 开红包的方法
- (void)OnOpenRedEnvelopes {
    // 得到成员变量 m_dicBaseInfo
    NSDictionary *dic = MSHookIvar<NSDictionary *>(self, "m_dicBaseInfo");
    // 打印字典
    for (NSString *key in dic) {
        NSString *value = dic[key];
        NSLog(@"Key: %@ Value: %@", key, value);
    }
    // 得到成员变量 m_delegate
    GofWeChatDelegate *delegate = MSHookIvar<GofWeChatDelegate *>(self, "m_delegate");
//    NSLog(@"%@", [delegate class]);
    [delegate WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes];
    // %orig;
}

%end

运行工程,可以看到使用我们自己的代码,也能进行抢红包了。接下来我们就重点分析方法【WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes】了。

  • 第五步:在【IDA】中,通过【Control + F】,搜索「WCRedEnvelopesReceiveControlLogic WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes」,找到【WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes】方法的汇编代码,可以看到,这个方法的汇编代码有 527 行,我们先看一下前面的几行:
; 这几句是读取成员变量 m_data 到 X21,结合头文件得到 m_data 的类型 伪代码:
; WCRedEnvelopesControlData *m_data = self.m_data;
_text:00000001015C108C                 ADRP            X8, #_OBJC_IVAR_$_WCRedEnvelopesControlLogic.m_data@PAGE ; WCRedEnvelopesControlData *m_data;
__text:00000001015C1090                 NOP
__text:00000001015C1094                 LDRSW           X21, [X8,#_OBJC_IVAR_$_WCRedEnvelopesControlLogic.m_data@PAGEOFF] ; WCRedEnvelopesControlData *m_data;
; 读取上面的变量到 X0,选择器 m_oSelectedMessageWrap 到 X1,调用 objc_msgSend 伪代码:
; CMessageWrap *msgWrap = [m_data m_oSelectedMessageWrap];
__text:00000001015C1098                 LDR             X0, [X27,X21] ; void *
__text:00000001015C109C                 ADRP            X8, #selRef_m_oSelectedMessageWrap@PAGE
__text:00000001015C10A0                 LDR             X19, [X8,#selRef_m_oSelectedMessageWrap@PAGEOFF]
__text:00000001015C10A4                 MOV             X1, X19 ; char *
__text:00000001015C10A8                 BL              _objc_msgSend
__text:00000001015C10AC                 MOV             X29, X29
__text:00000001015C10B0                 BL              _objc_retainAutoreleasedReturnValue
; 上一步返回值放到 X22  保存,选择器 m_oWCPayInfoItem 放入 X1,调用 objc_msgSend 伪代码:
; WCPayInfoItem *item = [msgWrap m_oWCPayInfoItem];
__text:00000001015C10B4                 MOV             X22, X0
__text:00000001015C10B8                 ADRP            X8, #selRef_m_oWCPayInfoItem@PAGE
__text:00000001015C10BC                 LDR             X1, [X8,#selRef_m_oWCPayInfoItem@PAGEOFF] ; char *
__text:00000001015C10C0                 STR             X1, [SP,#0x120+var_100]
__text:00000001015C10C4                 BL              _objc_msgSend
__text:00000001015C10C8                 MOV             X29, X29
__text:00000001015C10CC                 BL              _objc_retainAutoreleasedReturnValue
; 上一步返回值放到 X23 保存,选择器 m_c2cNativeUrl 放入 X1,调用 objc_msgSend 伪代码:
; NSString *url = [item m_c2cNativeUrl];
__text:00000001015C10D0                 MOV             X23, X0
__text:00000001015C10D4                 ADRP            X8, #selRef_m_c2cNativeUrl@PAGE
__text:00000001015C10D8                 LDR             X24, [X8,#selRef_m_c2cNativeUrl@PAGEOFF]
__text:00000001015C10DC                 MOV             X1, X24 ; char *
__text:00000001015C10E0                 BL              _objc_msgSend

上面的分析比较花费时间,实际上【IDA】可以自动生成伪代码,下面我们使用【IDA】生成的伪代码来进行分析,以提高效率。

  • 第六步:IDA 中,点击【View】-->【Open subviews】-->【Generate pseudocode】,生成伪代码(由于这个方法中有 Block,因此最好是先恢复 Block 的符号表):

  • 第七步:分析伪代码。
    ```
    void __cdecl -WCRedEnvelopesReceiveControlLogic WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes
    {
    // 结合汇编代码,可以知道 ((char *)&self->super.super.m_loadView + 1) 其实就是拿到 m_data 成员变量
    // 下面代码等价于: msgWrap 这里是 v3
    // WCRedEnvelopesControlData *m_data = self.m_data;
    // CMessageWrap msgWrap = [m_data m_oSelectedMessageWrap]; v2 = self; v3 = objc_msgSend((void **)((char *)&self->super.super.m_loadView + 1), "m_oSelectedMessageWrap");
    // v4 = v3 = msgWrap
    v4 = (void *)objc_retainAutoreleasedReturnValue(v3);
    // v5 = v4 = msgWrap
    v5 = v4;
    // 下面代码等价于:v6 = payInfoItem
    // WCPayInfoItem *payInfoItem = [msgWrap m_oWCPayInfoItem];
    v6 = objc_msgSend(v4, "m_oWCPayInfoItem");
    // v7 = v6 = payInfoItem
    v7 = (void *)objc_retainAutoreleasedReturnValue(v6);
    // v8 = v7 = payInfoItem
    v8 = v7;
    // 下面代码等价于:v9 = c2cNativeurl
    // NSString *c2cNativeurl = [payInfoitem m_c2cNativeUrl];
    v9 = objc_msgSend(v7, "m_c2cNativeUrl");
    // v10 = v9 = c2cNativeurl
    v10 = (void *)objc_retainAutoreleasedReturnValue(v9);
    // 下面代码等价于:v11 = len
    // NSUInteger len = [@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length];
    v11 = objc_msgSend(CFSTR("wxpay://c2cbizmessagehandler/hongbao/receivehongbao?"), "length");
    // 下面代码等价于:v12 = c2cNativeurl2
    // NSString *c2cNativeurl2 = [c2cNativeurl substringFromIndex:len];
    v12 = objc_msgSend(v10, "substringFromIndex:", v11);
    // v13 = v12 = c2cNativeurl2
    v13 = objc_retainAutoreleasedReturnValue(v12);
    objc_release(v10);
    objc_release(v8);
    objc_release(v5);
    //v90 = v13 = c2cNativeurl2
    v90 = v13;
    // 下面代码等价于:v14 = url_dic (返回值类型可以调试得到)
    // NSDictionary *url_dic = [WCBizUtil dictionaryWithDecodedComponets:c2cNativeurl2 separator:@"&"];
    v14 = +[WCBizUtil dictionaryWithDecodedComponets:separator:](
    &OBJC_CLASS___WCBizUtil,
    "dictionaryWithDecodedComponets:separator:",
    v13,
    CFSTR("&"));
    // v15 = v14 = url_dic
    v15 = (void *)objc_retainAutoreleasedReturnValue(v14);
    // 下面代码等价于:v16 = mutable_dic
    // NSMutableDictionary *mutable_dic = [%c(NSMutableDictionary) dictionary];
    v16 = objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "dictionary");
    // v17 = v16 = mutable_dic
    v17 = (void *)objc_retainAutoreleasedReturnValue(v16);
    // 下面代码等价于:
    // [mutable_dic setObject:@"1" forKey:@"msgType"];
    objc_msgSend(v17, "safeSetObject:forKey:", CFSTR("1"), CFSTR("msgType"));
    // 下面代码等价于:v18 = temp_sendid
    // id temp_sendid = [url_dic objectForKey:@"sendid"];
    v18 = objc_msgSend(v15, "objectForKey:", CFSTR("sendid"));
    // v19 = v18 = temp_sendid
    v19 = objc_retainAutoreleasedReturnValue(v18);
    // 下面代码等价于:
    // [mutable_dic setObject:temp_sendid forKey:@"sendId"];
    objc_msgSend(v17, "safeSetObject:forKey:", v19, CFSTR("sendId"));
    objc_release(v19);
    // v89 = v15 = url_dic
    v89 = v15;
    // 下面代码等价于:v20 = temp_channelId
    // id temp_channelId = [url_dic objectForKey:@"channelid"];
    v20 = objc_msgSend(v15, "objectForKey:", CFSTR("channelid"));
    // v21 = v20
    v21 = objc_retainAutoreleasedReturnValue(v20);
    // [mutable_dic setObject:temp_channelId forKey:@"channelId"];
    objc_msgSend(v17, "safeSetObject:forKey:", v21, CFSTR("channelId"));
    objc_release(v21);
    // 下面代码等价于:v22 = mmServiceCenter
    // MMServiceCenter *mmServiceCenter = [%c(MMServiceCenter) defaultCenter];
    v22 = objc_msgSend(&OBJC_CLASS___MMServiceCenter, "defaultCenter");
    // v23 = v22 = mmServiceCenter
    v23 = (void *)objc_retainAutoreleasedReturnValue(v22);
    // 下面代码等价于:v24 = ccontactMgr
    // Class ccontactMgr = [%c(CContactMgr) class];
    v24 = objc_msgSend(&OBJC_CLASS___CContactMgr, "class");
    // 下面代码等价于:v25 = service
    // CContactMgr *service = [mmServiceCenter getService:ccontactMgr];
    v25 = objc_msgSend(v23, "getService:", v24);
    // v26 = v25 = service
    v26 = (void *)objc_retainAutoreleasedReturnValue(v25);
    // v27 = v26 = service
    v27 = v26;
    // 下面代码等价于:v28 = selfContact
    // id selfContact = [service getSelfContact];
    v28 = objc_msgSend(v26, "getSelfContact");
    // v29 = v28 = selfContact
    v29 = (void *)objc_retainAutoreleasedReturnValue(v28);
    objc_release(v27);
    objc_release(v23);
    // 下面代码等价于:v30 = displayName
    // id displayName = [selfContact getContactDisplayName];
    v30 = objc_msgSend(v29, "getContactDisplayName");
    // v31 = v30 = displayName
    v31 = objc_retainAutoreleasedReturnValue(v30);
    // [mutable_dic setObject:displayName forKey:@"nickName"];
    objc_msgSend(v17, "safeSetObject:forKey:", v31, CFSTR("nickName"));
    objc_release(v31);
    // v88 = v29 = selfContact
    v88 = v29;
    // 下面代码等价于:v32 = headImgUrl
    // id headImgUrl = [selfContact m_nsHeadImgUrl];
    v32 = objc_msgSend(v29, "m_nsHeadImgUrl");
    // v33 = v32 = headImgUrl
    v33 = objc_retainAutoreleasedReturnValue(v32);
    // [mutable_dic setObject:headImgUrl forKey:@"headImg"];
    objc_msgSend(v17, "safeSetObject:forKey:", v33, CFSTR("headImg"));
    objc_release(v33);
    // 前面分析过:((char *)&self->super.super.m_loadView + 1) 其实就是拿到 m_data 成员变量,下面这两句代码在最开始有分析
    // v35 = v34 = msgWrap
    v34 = objc_msgSend(*(void **)((char *)&v2->super.super.m_loadView + 1), "m_oSelectedMessageWrap");
    v35 = objc_retainAutoreleasedReturnValue(v34);
    objc_release(v35);
    // if (msgWrap)
    if ( v35 )
    {
    // 下面这段代码和前面是一样的,执行之后的结果就是:
    // v43 = v42 = c2cNativeurl; 这里重新定义一个变量:
    // NSString nativeUrl = c2cNativeurl; v36 = objc_msgSend((void **)((char *)&v2->super.super.m_loadView + 1), "m_oSelectedMessageWrap");
    v37 = (void *)objc_retainAutoreleasedReturnValue(v36);
    v38 = v37;
    v39 = objc_msgSend(v37, "m_oWCPayInfoItem");
    v40 = (void *)objc_retainAutoreleasedReturnValue(v39);
    v41 = v40;
    v42 = objc_msgSend(v40, "m_c2cNativeUrl");
    v43 = objc_retainAutoreleasedReturnValue(v42);

    // [mutable_dic setObject:nativeUrl forKey:@"nativeUrl"];
    objc_msgSend(v17, "safeSetObject:forKey:", v43, CFSTR("nativeUrl"));
    objc_release(v43);
    objc_release(v41);
    objc_release(v38);
    }
    // [%c(MMServiceCenter) defaultCenter];
    v44 = objc_msgSend(&OBJC_CLASS___MMServiceCenter, "defaultCenter");
    v45 = (void *)objc_retainAutoreleasedReturnValue(v44);
    // [%c(MMMsgLogicManager) class];
    v46 = objc_msgSend(&OBJC_CLASS___MMMsgLogicManager, "class");
    // 下面代码等价于:v47 = redEnvelopsLogicMgr
    // MMMsgLogicManager *redEnvelopsLogicMgr = [[%c(MMServiceCenter) defaultCenter] getService:[%c(MMMsgLogicManager) class]];
    v47 = objc_msgSend(v45, "getService:", v46);
    // v48 = v47 = redEnvelopsLogicMgr
    v48 = (void *)objc_retainAutoreleasedReturnValue(v47);
    v49 = v48;
    // WeixinContentLogicController *currentLogicController = [redEnvelopsLogicMgr GetCurrentLogicController];
    v50 = objc_msgSend(v48, "GetCurrentLogicController");
    // v51 = v50 = currentLogicController
    v51 = (void *)objc_retainAutoreleasedReturnValue(v50);
    objc_release(v49);
    objc_release(v45);
    // if (currentLogicController)
    if ( v51 )
    {
    // CBaseContact *m_contact = [currentLogicController m_contact];
    v52 = objc_msgSend(v51, "m_contact");
    // v53 = v52 = m_contact
    v53 = objc_retainAutoreleasedReturnValue(v52);
    // if (m_contact)
    if ( v53 )
    {
    // CBaseContact *contact = [currentLogicController m_contact];
    v54 = objc_msgSend(v51, "m_contact");
    // v55 = v54 = contact
    v55 = (void *)objc_retainAutoreleasedReturnValue(v54);
    v56 = v55;
    // NSString *nsUsrName = [contact m_nsUsrName];
    v57 = objc_msgSend(v55, "m_nsUsrName");
    // v58 = v57 = nsUsrName
    v58 = objc_retainAutoreleasedReturnValue(v57);
    objc_release(v58);
    objc_release(v56);
    objc_release(v53);
    // if (nsUsrName)
    if ( v58 )
    {
    v59 = objc_msgSend(v51, "m_contact");
    v60 = (void *)objc_retainAutoreleasedReturnValue(v59);
    v61 = v60;
    v62 = objc_msgSend(v60, "m_nsUsrName");
    v63 = objc_retainAutoreleasedReturnValue(v62);
    // [mutable_dic setObject:nsUsrName forKey:@"sessionUserName"];
    objc_msgSend(v17, "safeSetObject:forKey:", v63, CFSTR("sessionUserName"));
    objc_release(v63);
    objc_release(v61);
    }
    }
    }
    // NSDictionary m_dicBaseInfo = [m_data m_structDicRedEnvelopesBaseInfo]; v64 = objc_msgSend((void **)((char *)&v2->super.super.m_loadView + 1), "m_structDicRedEnvelopesBaseInfo");

    v65 = (void *)objc_retainAutoreleasedReturnValue(v64);
    // v66 = v65 = v64 = m_dicBaseInfo
    v66 = v65;
    // NSString *timeIdentifier = [m_dicBaseInfo stringForKey:@"timingIdentifier"];
    v67 = objc_msgSend(v65, "stringForKey:", CFSTR("timingIdentifier"));
    // v68 = v67 = timeIdentifier

top Created with Sketch.