iOS逆向工程女程序猿程序员

iOS逆向篇之微信抢红包(上)

2018-05-25  本文已影响205人  meryin

本文仅供学习和参考,建议不用于商业用途,若用于商业用途后果自负
完整的工程地址

一 设置界面添加抢红包功能

在设置界面添加抢红包开关和延迟时间的两个cell

  1. 建立MonkeyApp工程,把微信ipa拖到TargetApp文件夹中,真机运行
  2. 用Xcode的Debug view找到设置界面的代码注入的地方


    11.png
(lldb) po 0x117964b60
delegate[0x11793f130], class[MMTableViewInfo]
@interface MMTableViewInfo : MMTableViewUserInfo <UITableViewDelegate, UITableViewDataSource, tableViewDelegate>
{
    MMTableView *_tableView;
    NSMutableArray *_arrSections;
    id <MMTableViewInfoDelegate> _delegate;
    _Bool _disableAutoDeselectRows;
}
- (id)tableView:(id)arg1 cellForRowAtIndexPath:(id)arg2;
- (long long)tableView:(id)arg1 numberOfRowsInSection:(long long)arg2;
- (long long)numberOfSectionsInTableView:(id)arg1;

可以看出NewSettingViewController主要由MMTableViewInfo的MMTableView *_tableView构成
由此分析得到想在设置界面添加两个cell,要在MMTableViewInfo类中的tableView代理中设置

  1. 代码注入
%hook MMTableViewInfo

- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)])//定位到设置界面
    {
        if([indexPath section] == [self numberOfSectionsInTableView:tableView]-1){
            UITableViewCell * cell = nil;
            if([indexPath row] == 0){
                static NSString * switchCell = @"switchCell";
                cell = [tableView dequeueReusableCellWithIdentifier:switchCell];
                if(!cell){
                    cell  = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:switchCell];
                }
               
                cell.textLabel.text = @"自动抢红包";
                UISwitch * switchView = [[UISwitch alloc] init];
                cell.accessoryView = switchView;
                
            }else if([indexPath row] == 1){
                static NSString * waitCell = @"waitCell";
                cell = [tableView dequeueReusableCellWithIdentifier:waitCell];
                if(!cell){
                    cell  = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:waitCell];
                }
                cell.textLabel.text = @"等待时间(秒)";
                UITextField * textField = [[UITextField alloc] initWithFrame:CGRectMake(0,0,150,40)];
                textField.placeholder = @"等待时间";
                textField.borderStyle = UITextBorderStyleRoundedRect;
                cell.accessoryView = textField;
                 //监听键盘输入
                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChangeValue:) name:UITextFieldTextDidChangeNotification object:textField];
                textField.text = [WCDefaults valueForKey:WCTIMEKEY];
            }
            
            cell.backgroundColor = [UIColor whiteColor];
            return cell;
        }
        return %orig;
        
    }
    return %orig;
}
- (long long)tableView:(UITableView *)arg1 numberOfRowsInSection:(NSInteger)section
{
    if([arg1.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)])//定位到设置界面
    {
        NSMutableArray *arr = MSHookIvar<NSMutableArray *>(self,"_arrSections");
        NSLog(@"--%@",arr);
        if(section == [self numberOfSectionsInTableView:arg1]-1)
        {NSLog(@"xxx--%@",arg1);
            return 2;
        }
        return %orig;
    }
    return %orig;
}
- (long long)numberOfSectionsInTableView:(UITableView *)arg1
{
    if([arg1.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)])//定位到设置界面
    {
       
        return %orig+1;
    }
    return %orig;
}
- (double)tableView:(UITableView *)tableView heightForRowAtIndexPath:(id)indexPath{
    //定位设置界面&&最后一组
    if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]
       && [indexPath section] == [self numberOfSectionsInTableView:tableView]-1){
        return 44;
        
    }
    
    return %orig;
}

%end
  1. 本地数据缓存
#define WCDefaults [NSUserDefaults standardUserDefaults]
#define WCSWITCHKEY @"WCSWITCHKEY"
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
       switchView.on = [WCDefaults boolForKey:WCSWITCHKEY];
       [switchView addTarget:self action:@selector(switchChang:) forControlEvents:(UIControlEventValueChanged)];
....
}
%new
-(void)switchChang:(UISwitch *)switchView{
    [WCDefaults setBool:switchView.isOn forKey:WCSWITCHKEY];
    [WCDefaults synchronize];
}
%new
- (void)textFieldDidChangeValue:(NSNotification *)notification{
    
    UITextField *sender = (UITextField *)[notification object];
    [WCDefaults setValue:sender.text forKey:WCTIMEKEY];
    [WCDefaults synchronize];
}

二 hook到收到红包消息的方法

  1. 分析聊天界面构成
  1. 找到BaseMsgContentViewController后就需要找到哪个方法是红包消息方法,可以hook所有方法,然后打印输出。手动方法(不建议)
logify.pl /Users/mac/Desktop/wechatHeaders/BaseMsgContentViewController.h > ./BaseMsgContentViewControllerHook.xm
  1. 上面hook所有方法的方式太慢,MonkeyApp可以直接完成(速度很快)
  1. hook消息方法
//红包逻辑分析
%group group4
%hook BaseMsgContentViewController

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

%end

断点到addMessageNode,然后po arg1可以看出addMessageNode方法就是消息收发相关的方法,那么当新消息来的时候,查看函数调用栈,就知道是哪个对象在管理消息的收发。可以通过恢复符号表找到这个对象

  1. 利用restore-symbol 恢复符号表
  1. 恢复符号表后运行,收到新消息的函数调用栈:bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
    frame #0: 0x00000001078189dc lib003--WeiChatTestDylib.dylib`_logos_method$group4$BaseMsgContentViewController$addMessageNode$layout$addMoreMsg$(self=0x00000001089b1e00, _cmd="addMessageNode:layout:addMoreMsg:", arg1=0x00000001166881a0, arg2=true, arg3=false) at _03__WeiChatTestDylib.xm:217
  * frame #1: 0x0000000102d7f3ec WeChat`-[BaseMsgContentLogicController DidAddMsg:] + 520
    frame #2: 0x0000000102d67250 WeChat`-[BaseMsgContentLogicController OnAddMsg:MsgWrap:] + 360
    frame #3: 0x0000000106603980 MMCommon`_callExtension + 480
    frame #4: 0x0000000103647dd4 WeChat`-[CMessageMgr MainThreadNotifyToExt:] + 560
    frame #5: 0x00000001850ca0ec Foundation`__NSThreadPerformPerform + 340

可以看出frame #4: 0x0000000103647dd4 WeChat`-[CMessageMgr MainThreadNotifyToExt:]就是消息中转站
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

可以分析出CMessageMgr这个类就是消息中转站

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

输出:

 {m_uiMesLocalID=9, m_ui64MesSvrID=6148490851876887842, m_nsFromUsr=wxi*241~19, m_nsToUsr=wxi*l12~19, m_uiStatus=3, type=1, msgSource="<msgsource><sequence_id>634140695</sequence_id></msgsource>"} 
CMessageWrap

分析CMessageWrap的type=49的时候是红包消息

三 hook开红包的方法

  1. 找到开红包的按钮
cy# #0x10eb580b0.text = "meryin"
"meryin"
cy# [#0x10eb580b0 nextResponder]
#"<UIImageView: 0x10c4c18c0; frame = (25 116.5; 325 434); autoresize = LM+RM+TM+BM; layer = <CALayer: 0x10d061800>>"
cy# # 0x10c4c18c0.subviews

所有子控件中有两个UIButton,根据其frame,找到并验证UIButton: 0x116d71840; frame = (107.5 233; 110 110)就是拆红包按钮

  1. 找到拆红包按钮的target
cy# #0x116d71840.allTargets
[NSSet setWithArray:@[#"<WCRedEnvelopesReceiveHomeView: 0x11393a310; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x10d3a4e40>>"]]]

WCRedEnvelopesReceiveHomeView就是UIButton 的target

  1. 找到拆红包的方法
    利用cyprit 一个方法一个方法的试:
cy# [#0x11393a310 OnOpenRedEnvelopes]

WCRedEnvelopesReceiveHomeView 类中的OnOpenRedEnvelopes就是开红包的方法
以上只能在拆红包界面才能自动拆红包,我们的目的是,无论在哪个界面或者后台运行,只要红包消息来了就能自动拆红包

  1. 静态分析OnOpenRedEnvelopes
#_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_dicBaseInfo@PAGE
__text:0000000101157290                 LDRSW           X24, [X8,#_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_dicBaseInfo@PAGEOFF] ; NSDictionary *m_dicBaseInfo;
.....
#_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_delegate@PAGE
__text:0000000101157378                 LDRSW           X8, [X8,#_OBJC_IVAR_$_WCRedEnvelopesReceiveHomeView.m_delegate@PAGEOFF] ; WCRedEnvelopesReceiveHomeViewDelegate *m_delegate;
#selRef_WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes@PAGE
[X8,#selRef_WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes@PAGEOFF]
__text:0000000101157390                 BL              _objc_msgSend

分析可以看出这个方法大概执行了,拿到 NSDictionary *m_dicBaseInfo做一系列判定,然后拿到id <WCRedEnvelopesReceiveHomeViewDelegate> m_delegate;然后m_delegate发送消息WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes

%hook WCRedEnvelopesReceiveHomeView
- (void)OnOpenRedEnvelopes{
    NSDictionary *dict = MSHookIvar<NSDictionary*>(self,"m_dicBaseInfo");
    NSArray *arr = dict.allKeys;
    for(int i=0;i<arr.count;i++){
        NSLog(@"%@:%@",arr[i],[dict objectForKey:arr[i]]);
    }
    id delegate = MSHookIvar<id >(self,"m_delegate");
    NSLog(@"---%@",[delegate class]);
}
%end

打印输出:

2018-05-23 17:51:00.011658+0800 WeChat[9997:949894] wishing:恭喜发财,大吉大利
2018-05-23 17:51:00.011940+0800 WeChat[9997:949894] watermark:
2018-05-23 17:51:00.012051+0800 WeChat[9997:949894] sendUserName:wxid_hy6hye79l4q241
2018-05-23 17:51:00.012153+0800 WeChat[9997:949894] timingIdentifier:7149DB99A65AA9FDEAC9095342D16F8D
2018-05-23 17:51:00.012487+0800 WeChat[9997:949894] hbStatus:2
2018-05-23 17:51:00.012603+0800 WeChat[9997:949894] receiveStatus:0
2018-05-23 17:51:00.012757+0800 WeChat[9997:949894] sendId:1000039401201805237018373647074
2018-05-23 17:51:00.012921+0800 WeChat[9997:949894] isSender:0
2018-05-23 17:51:00.013326+0800 WeChat[9997:949894] statusMess:给你发了一个红包
2018-05-23 17:51:00.013543+0800 WeChat[9997:949894] hbType:0
2018-05-23 17:51:00.013752+0800 WeChat[9997:949894] ---WCRedEnvelopesReceiveControlLogic

可以看出拆红包的核心代码就是WCRedEnvelopesReceiveControlLogic类中的 WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes方法

  1. 静态分析 WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes
    ida找到ctrl+f键找到WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes方法,然后按f5就可以还原伪代码
    调用类方法 [%c(类名称) 方法名]
%hook WCRedEnvelopesReceiveControlLogic
- (void)WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes{
    WCRedEnvelopesControlData *m_data =  MSHookIvar<WCRedEnvelopesControlData* >(self,"m_data");
    CMessageWrap *m_Wrap =[m_data m_oSelectedMessageWrap];
    WCPayInfoItem *item =[m_Wrap m_oWCPayInfoItem];
    NSString *url =[item  m_c2cNativeUrl];
    NSInteger length = [@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length];
    id componets = [url substringFromIndex:length];
    //调用类方法 [%c(类名称)  方法名]
    NSDictionary *dictionary=[%c(WCBizUtil) dictionaryWithDecodedComponets:componets separator:@"&"];
    NSLog(@"dic===%@",dictionary);
        NSMutableDictionary *mul_dict =[%c(NSMutableDictionary) dictionary];
        [mul_dict setObject:@"1" forKey:@"msgType"];
        [mul_dict setObject:dictionary[@"sendid"] forKey:@"sendId"];
        [mul_dict setObject:dictionary[@"channelid"] forKey:@"channelId"];
        CContactMgr *server =[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]];
        CContact *contact = [server getSelfContact];
        id  displayName = [contact getContactDisplayName];
        [mul_dict setObject:displayName forKey:@"nickName"];
        id m_nsHeadImgUrl = [contact m_nsHeadImgUrl];
        [mul_dict setObject:m_nsHeadImgUrl forKey:@"headImg"];
        CMessageWrap *warp =[m_data m_oSelectedMessageWrap];
        if ( warp )
        {
            [mul_dict setObject:url forKey:@"nativeUrl"];
        }
        MMMsgLogicManager *logicserver =[[%c(MMServiceCenter) defaultCenter] getService:[%c(MMMsgLogicManager) class]];
        WeixinContentLogicController *currentLogicController = [logicserver GetCurrentLogicController];
       NSLog(@"--%@",[currentLogicController class]);
        if ( currentLogicController )
        {
            id m_contact =[currentLogicController m_contact];
            if ( m_contact )
            {
                NSString *m_nsUsrName =[m_contact m_nsUsrName];
                if ( m_nsUsrName )
                {
                    [mul_dict setObject:m_nsUsrName forKey:@"sessionUserName"];
                }
            }
        }
        NSDictionary  *m_struct = [m_data m_structDicRedEnvelopesBaseInfo];
        NSString *timingIdentifier= [m_struct objectForKey:@"timingIdentifier"]
        if ( [timingIdentifier length])
        { [mul_dict setObject:timingIdentifier forKey:@"timingIdentifier"];}
       WCPayLogicMgr *payLogicMgr =[[%c(MMServiceCenter) defaultCenter] getService:[%c(WCPayLogicMgr) class]];
        [payLogicMgr setRealnameReportScene:1003];
      id subScript = [m_struct objectForKeyedSubscript:@"agree_duty"];
    /*
        v97 = _NSConcreteStackBlock;
        v98 = 3254779904LL;
        v99 = sub_1015C17E0;
        v100 = &unk_10390BBD0;
        v101 = v17;
        v86 = objc_retain(v17);
        v87 = objc_retain(v72);
        v102 = v87;
        v91 = _NSConcreteStackBlock;
        v92 = 3254779904LL;
        v93 = sub_1015C18F8;
        v94 = &unk_10390BC00;
        objc_copyWeak(&v96, &v103);
        v95 = objc_retain(v87);
        objc_msgSend(v80, "checkHongbaoOpenLicense:acceptCallback:denyCallback:", v85, &v97, &v91);
     */

}
%end

以上除了block其他都还原了

  1. 还原block符号表
 [payLogicMgr checkHongbaoOpenLicense:subScript acceptCallback:^(){
       WCRedEnvelopesLogicMgr *envelopesLogicMgr = [[%c(MMServiceCenter) defaultCenter] getService:[%c(WCRedEnvelopesLogicMgr) class]];
        [envelopesLogicMgr OpenRedEnvelopesRequest:mul_dict];
    }denyCallback:^(){
        
    }];

可以分析出WCRedEnvelopesLogicMgr就是红包管理类,OpenRedEnvelopesRequest:就是开红包的关键方法

接下篇

上一篇下一篇

猜你喜欢

热点阅读