iOS逆向及安全

iOS逆向实战(二)- 抖音之播放记录

Posted on 2020-06-17,4 min read
封面图

抖音现在基本成了每个人手机里必备的软件,不过还是有些功能不够完善。比如我正在看一个视频的时候,不小心刷新了,那么我就很难再找到这个视频继续看。那么今天我就自己动手给抖音添加一个小功能之播放历史记录。

那么今天我就先不讲如何逆向实现播放记录功能,先看看被我动过刀的抖音变得如何。

  • 为了方便快捷的找到历史记录列表,在我的界面增加一个历史记录的按钮,跳转到历史记录列表
  • 列表中主要展示作者信息,和当前所看视频的信息
  • 点击列表展开附加功能,包含复制抖音号、下载当前视频音视频、以及播放当前视频

逆向分析要点

  • 通过Reveal分析,首先找到视频播控制器

  • 找到控制器所对应的视频Model, 分析当前播放视频所对应的Model,然后通过全局单例数组保存
  • 创建列表展示数据,分析model取出对应的音视频Url、用户信息等,实现对应小功能。

关键Hook代码


#import <UIKit/UIKit.h>
#import "HistoryListViewController.h"

@interface AWEAwemeModel

@property(copy, nonatomic) NSString *itemID;
@property(copy, nonatomic) NSString *descriptionString;

@end


@interface AWEFeedTableViewController

@end


@interface AWEAwemePlayVideoViewController

@property(retain, nonatomic) AWEAwemeModel *repostItem;
@property(retain, nonatomic) AWEAwemeModel *model; 

- (_Bool)play;
- (_Bool)stop;

@end

@interface AWEUserPostsDataManager

@property(retain, nonatomic) NSMutableArray *localPosts; 

@end

@interface AWEMaskWindow

@property (nonatomic ,strong) NSMutableArray *dataArray;

@property (nonatomic ,strong) AWEAwemePlayVideoViewController *playerVC;

@end

@interface AWEProfileSocialStatisticView

- (void)layoutSubviews;
- (void)addSubview:(UIView *)view;
@end

%hook AWEProfileSocialStatisticView

- (void)layoutSubviews{

     UIButton *historyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    historyBtn.frame = CGRectMake([[UIScreen mainScreen] bounds].size.width - 95,0, 80, 20);
    historyBtn.titleLabel.font = [UIFont boldSystemFontOfSize:14];
    [historyBtn setTitle:@"历史记录" forState:UIControlStateNormal];
    [historyBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [historyBtn addTarget:self action:@selector(actionForHistory) forControlEvents:UIControlEventTouchUpInside];

    UITabBarController *tabbarVC = (UITabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
    UINavigationController *navVC = tabbarVC.selectedViewController;
    if (navVC.childViewControllers.count == 1) {
        [self addSubview:historyBtn];
    }
    

    NSLog(@"xby-023");

    return %orig;
     
}

%new
- (void)actionForHistory{
    NSLog(@"xby-023");
    UITabBarController *tabbarVC = (UITabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
    UINavigationController *navVC = tabbarVC.selectedViewController;
    UIViewController *vc = navVC.childViewControllers.lastObject;
    vc.hidesBottomBarWhenPushed = YES;
    [vc.navigationController pushViewController:[[HistoryListViewController alloc] init] animated:YES];
    NSLog(@"xby count:%ld",navVC.childViewControllers.count);
    if (navVC.childViewControllers.count == 2) {
        vc.hidesBottomBarWhenPushed = NO;
    }
}

%end


%hook AWEMaskWindow

// 添加属性
%property (nonatomic ,strong) NSMutableArray *dataArray;
%property (nonatomic ,strong) AWEAwemePlayVideoViewController *playerVC;

%end




%hook AWEFeedTableViewController


// 当前一条
- (id)fetchPreloadedCellForRowWithModel:(AWEAwemeModel *)arg1 atIndexPath:(id)arg2{
	
    // AWEMaskWindow *tabbarVC = (AWEMaskWindow *)[UIApplication sharedApplication].keyWindow;

    // if (!tabbarVC.dataArray)
    // {
    // 	tabbarVC.dataArray = [NSMutableArray array];
    // }
    
    // //判断是否添加数据
    // __block BOOL ok = YES;
    // [tabbarVC.dataArray enumerateObjectsUsingBlock:^(AWEAwemeModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
    //     if ([obj.itemID isEqualToString:arg1.itemID]) {
    //         ok = NO;
    //     }
    // }];

    // if (arg1.descriptionString.length == 0)
    // {
    // 	ok = NO;
    // }

    // //更新数据
    // if (ok) {
    //     [tabbarVC.dataArray insertObject:arg1 atIndex:0];
    // }
    
	return %orig;
}


// 下一条
- (void)configureCell:(id)arg1 withModel:(id)arg2 atIndexPath:(id)arg3{
	%orig;
}

%end

%hook AWEAwemePlayVideoViewController

- (void)setModel:(AWEAwemeModel *)arg1{
  
    if (arg1){
    	     AWEMaskWindow *tabbarVC = (AWEMaskWindow *)[UIApplication sharedApplication].keyWindow;
    	     
             if (!tabbarVC.playerVC)
             {
                 tabbarVC.playerVC = self;
             }

		    if (!tabbarVC.dataArray)
		    {
		    	tabbarVC.dataArray = [NSMutableArray array];
		    }
		    
		    //判断是否添加数据
		    __block BOOL ok = YES;
		    [tabbarVC.dataArray enumerateObjectsUsingBlock:^(AWEAwemeModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
		        if ([obj.itemID isEqualToString:arg1.itemID]) {
		            ok = NO;
		        }
		    }];

		    if (arg1.descriptionString.length == 0)
		    {
		    	ok = NO;
		    }

		    //更新数据
		    if (ok) {
		        [tabbarVC.dataArray insertObject:arg1 atIndex:0];
		    }

		    NSLog(@"xby-023 - %@",arg1);
    }

	%orig;
}

- (void)viewDidAppear:(_Bool)arg1{
    %orig;
    NSLog(@"xby -play");
    // [self play];
}

- (_Bool)play{
	return %orig;
}

- (void)viewDidDisappear:(_Bool)arg1{
    %orig;
    NSLog(@"xby -stop");
    // [self stop];
}


- (_Bool)stop{
    return %orig;
}

%end

总结:此次实战的难点主要在找准model,对数据进行分析,并对数据进行处理来达到想要的效果。若有什么问题,欢迎探讨!


下一篇: iOS杂谈 - 无侵入的埋点方案→